diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 216410ec2..01a80fbcd 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -5,3 +5,5 @@ c07a4aa4b61aab90a4e3927fd83574158907be27 77891f15aaff2826a65338edf0448625f3982295 # Flatten multi-level style of module composition 1fed30132333efa675f0c7d800691a225e9c26f8 +# Run bin/standardrb --fix +c23ea233adc828e9a8c6d02143279269f551a23f diff --git a/Gemfile b/Gemfile index 48e9edf9a..a17baced0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,170 +1,167 @@ -source 'https://rubygems.org' +source "https://rubygems.org" -ruby ENV['CUSTOM_RUBY_VERSION'] || '3.1.7' # heroku needs a specific ruby version in the Gemfile +ruby ENV["CUSTOM_RUBY_VERSION"] || "3.1.7" # heroku needs a specific ruby version in the Gemfile -gem 'rake' -gem 'rails', '~> 7.0.8.7' -gem 'sprockets', '~> 3.7' # Sprockets 4.0 stops allowing us to add a proc to the config.assets.precompile array, which we currently use +gem "rake" +gem "rails", "~> 7.0.8.7" +gem "sprockets", "~> 3.7" # Sprockets 4.0 stops allowing us to add a proc to the config.assets.precompile array, which we currently use -gem 'rack', '~> 2.2.13' +gem "rack", "~> 2.2.13" # https://stripe.com/docs/api -gem 'stripe', '~> 5.0' +gem "stripe", "~> 5.0" # json serialization # https://github.com/nesquena/rabl -gem 'rabl' +gem "rabl" -gem 'jbuilder' +gem "jbuilder" gem "puma", "~> 5.6" -gem 'kaminari' +gem "kaminari" -gem 'bootsnap', require: false -gem 'rack-timeout' +gem "bootsnap", require: false +gem "rack-timeout" -gem 'test-unit' -gem 'immutable-ruby' # used instead of hamster in a few legacy places +gem "test-unit" +gem "immutable-ruby" # used instead of hamster in a few legacy places -gem 'aws-sdk-s3' -gem 'aws-sdk-rails' +gem "aws-sdk-s3" +gem "aws-sdk-rails" -gem 'json', '>= 2.3.0' +gem "json", ">= 2.3.0" -gem 'yaaf' # form objects +gem "yaaf" # form objects # for blocking ip addressses -gem 'rack-attack' +gem "rack-attack" # to find middleware thread safety bugs -gem 'rack-freeze' +gem "rack-freeze" # Database (postgres) -gem 'pg', '~> 1.1' -gem 'qx', path: 'gems/ruby-qx' -gem 'dalli' +gem "pg", "~> 1.1" +gem "qx", path: "gems/ruby-qx" +gem "dalli" - -gem 'param_validation', path: 'gems/ruby-param-validation' +gem "param_validation", path: "gems/ruby-param-validation" # Print colorized text lol -gem 'colorize' +gem "colorize" # https://github.com/collectiveidea/delayed_job_active_record -gem 'delayed_job_active_record' +gem "delayed_job_active_record" # For nat lang parsing of dates -gem 'chronic' +gem "chronic" # Images # https://github.com/carrierwaveuploader/carrierwave -gem 'carrierwave', '~> 3.0' -gem 'carrierwave-aws' # for uploading images to amazon s3 -gem 'mini_magick' +gem "carrierwave", "~> 3.0" +gem "carrierwave-aws" # for uploading images to amazon s3 +gem "mini_magick" # https://github.com/jnunemaker/httparty -gem 'httparty' +gem "httparty" # User authentication # https://github.com/plataformatec/devise -gem 'devise', '~> 4.1' +gem "devise", "~> 4.1" # https://github.com/airbrake/airbrake -gem 'airbrake' +gem "airbrake" # http://www.rubygeocoder.com/ -gem 'geocoder' # for adding latitude and longitude to location-based tables +gem "geocoder" # for adding latitude and longitude to location-based tables # https://github.com/buytruckload/nearest_time_zone -gem 'nearest_time_zone' # for detecting timezone from lat/lng +gem "nearest_time_zone" # for detecting timezone from lat/lng -gem 'rest-client' # recommended for fullcontact +gem "rest-client" # recommended for fullcontact # https://github.com/fphilipe/premailer-rails # for stylizing emails -gem 'premailer-rails' +gem "premailer-rails" # Nice table printing of data for the console -gem 'table_print' +gem "table_print" -gem 'rails-i18n' # For 4.0.x -gem 'i18n-js', '~> 3.8' # i18n-js 4 is very different and doesn't work without some big changes -gem 'countries' +gem "rails-i18n" # For 4.0.x +gem "i18n-js", "~> 3.8" # i18n-js 4 is very different and doesn't work without some big changes +gem "countries" -gem 'rexml' # needed on Ruby 3 +gem "rexml" # needed on Ruby 3 group :development, :ci, :test do gem "standard" gem "standard-rails" - gem 'listen' - gem 'letter_opener' - gem 'timecop' - gem 'pry' - gem 'pry-byebug' - gem 'binding_of_caller' - gem 'rspec', "~> 3" - gem 'rspec-rails', "~> 7" - gem 'database_cleaner' - gem 'dotenv-rails' - gem 'stripe-ruby-mock', '~> 5.0', :require => 'stripe_mock' - gem 'factory_bot' - gem 'factory_bot_rails' - gem 'action_mailer_matchers', '~> 1.2.0' - gem 'simplecov', '~> 0.22.0', require: false - gem 'byebug' - gem 'shoulda-matchers' - gem 'rspec-json_expectations' - gem 'yard' - gem 'faker' # test data generation + gem "listen" + gem "letter_opener" + gem "timecop" + gem "pry" + gem "pry-byebug" + gem "binding_of_caller" + gem "rspec", "~> 3" + gem "rspec-rails", "~> 7" + gem "database_cleaner" + gem "dotenv-rails" + gem "stripe-ruby-mock", "~> 5.0", require: "stripe_mock" + gem "factory_bot" + gem "factory_bot_rails" + gem "action_mailer_matchers", "~> 1.2.0" + gem "simplecov", "~> 0.22.0", require: false + gem "byebug" + gem "shoulda-matchers" + gem "rspec-json_expectations" + gem "yard" + gem "faker" # test data generation end - group :test do - gem 'webmock' + gem "webmock" end # Gems used for asset compilation -gem 'sassc' -gem 'sassc-rails' -gem 'uglifier' +gem "sassc" +gem "sassc-rails" +gem "uglifier" # make logging less terrible in rails -gem 'lograge' +gem "lograge" -gem 'config', '~> 2.0' -gem 'dry-validation' # used only for config validation +gem "config", "~> 2.0" +gem "dry-validation" # used only for config validation group :production do - gem 'rails_autoscale_agent', '>= 0.9.1' - gem 'tunemygc' + gem "rails_autoscale_agent", ">= 0.9.1" + gem "tunemygc" end - group :production, :staging do gem "hiredis", "~> 0.6.0" gem "redis", ">= 3.2.0" - gem 'redis-actionpack' + gem "redis-actionpack" end -gem 'recaptcha', '~> 5.8.1' +gem "recaptcha", "~> 5.8.1" -gem 'hashie' +gem "hashie" -gem 'connection_pool' +gem "connection_pool" gem "barnes" -gem 'protected_attributes_continued' # because we upgraded from 3 and then 4 +gem "protected_attributes_continued" # because we upgraded from 3 and then 4 -gem 'rack-cors' +gem "rack-cors" -gem 'fx' +gem "fx" -gem 'has_scope' +gem "has_scope" -gem 'globalid', ">= 1.0.1" +gem "globalid", ">= 1.0.1" -gem 'js-routes' +gem "js-routes" -gem 'concurrent-ruby', '1.3.4' # there's a regression in 1.3.5 that can be removed at Rails 7.1 +gem "concurrent-ruby", "1.3.4" # there's a regression in 1.3.5 that can be removed at Rails 7.1 diff --git a/Rakefile b/Rakefile index baff55158..6c29723c5 100755 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require File.expand_path("../config/application", __FILE__) Rails.application.load_tasks diff --git a/app/controllers/api_new/api_controller.rb b/app/controllers/api_new/api_controller.rb index 827f73a0c..1647a00d2 100644 --- a/app/controllers/api_new/api_controller.rb +++ b/app/controllers/api_new/api_controller.rb @@ -3,24 +3,24 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module ApiNew - class ApiController < ActionController::Base # rubocop:disable Rails/ApplicationController - # We disable Rails/ApplicationController because we don't want all the stuff in ApplicationController included since - # the Api is simpler - include Controllers::Locale - include Controllers::Nonprofit::Authorization - include Controllers::ApiNew::JbuilderExpansions - rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_rescue - rescue_from AuthenticationError, with: :unauthorized_rescue + class ApiController < ActionController::Base # rubocop:disable Rails/ApplicationController + # We disable Rails/ApplicationController because we don't want all the stuff in ApplicationController included since + # the Api is simpler + include Controllers::Locale + include Controllers::Nonprofit::Authorization + include Controllers::ApiNew::JbuilderExpansions + rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_rescue + rescue_from AuthenticationError, with: :unauthorized_rescue - protected + protected - def record_invalid_rescue(error) - render json: { errors: error.record.errors.messages }, status: :unprocessable_entity - end + def record_invalid_rescue(error) + render json: {errors: error.record.errors.messages}, status: :unprocessable_entity + end - def unauthorized_rescue(error) - @error = error - render 'api_new/errors/unauthorized', status: :unauthorized - end - end -end \ No newline at end of file + def unauthorized_rescue(error) + @error = error + render "api_new/errors/unauthorized", status: :unauthorized + end + end +end diff --git a/app/controllers/api_new/object_events_controller.rb b/app/controllers/api_new/object_events_controller.rb index 7677f99d7..2939bb1ca 100644 --- a/app/controllers/api_new/object_events_controller.rb +++ b/app/controllers/api_new/object_events_controller.rb @@ -4,20 +4,20 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module ApiNew - class ObjectEventsController < ApiNew::ApiController - include Controllers::ApiNew::Nonprofit::Current - include Controllers::Nonprofit::Authorization - before_action :authenticate_nonprofit_user! + class ObjectEventsController < ApiNew::ApiController + include Controllers::ApiNew::Nonprofit::Current + include Controllers::Nonprofit::Authorization + before_action :authenticate_nonprofit_user! - has_scope :event_entity - has_scope :event_types, type: :array + has_scope :event_entity + has_scope :event_types, type: :array - # Gets the nonprofits object events - # If not logged in, causes a 401 error - def index - @object_events = apply_scopes(current_nonprofit - .associated_object_events) - .order('created_at DESC').page(params[:page]).per(params[:per]) - end - end + # Gets the nonprofits object events + # If not logged in, causes a 401 error + def index + @object_events = apply_scopes(current_nonprofit + .associated_object_events) + .order("created_at DESC").page(params[:page]).per(params[:per]) + end + end end diff --git a/app/controllers/api_new/offline_transaction_charges_controller.rb b/app/controllers/api_new/offline_transaction_charges_controller.rb index b74b0f544..f86676f8b 100644 --- a/app/controllers/api_new/offline_transaction_charges_controller.rb +++ b/app/controllers/api_new/offline_transaction_charges_controller.rb @@ -6,4 +6,4 @@ # Rails 6 requires a matching controller for the `spec/views/api_new/offline_transaction_charges/show.json.jbuilder_spec.rb` spec # This controller isn't currently used for anything else. class ApiNew::OfflineTransactionChargesController < ApiNew::ApiController -end \ No newline at end of file +end diff --git a/app/controllers/api_new/payouts_controller.rb b/app/controllers/api_new/payouts_controller.rb index 646e1155d..a74bb9e02 100644 --- a/app/controllers/api_new/payouts_controller.rb +++ b/app/controllers/api_new/payouts_controller.rb @@ -6,4 +6,4 @@ # Rails 6 requires a matching controller for the `spec/views/api_new/payouts/show.json.jbuilder_spec.rb` spec # This controller isn't currently used for anything else. class ApiNew::PayoutsController < ApiNew::ApiController -end \ No newline at end of file +end diff --git a/app/controllers/api_new/supporters_controller.rb b/app/controllers/api_new/supporters_controller.rb index d41e42c4a..e100f7f45 100644 --- a/app/controllers/api_new/supporters_controller.rb +++ b/app/controllers/api_new/supporters_controller.rb @@ -4,22 +4,22 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module ApiNew - # A controller for interacting with a nonprofit's supporters - class SupportersController < ApiNew::ApiController - include Controllers::ApiNew::Nonprofit::Current - include Controllers::Nonprofit::Authorization - before_action :authenticate_nonprofit_user! + # A controller for interacting with a nonprofit's supporters + class SupportersController < ApiNew::ApiController + include Controllers::ApiNew::Nonprofit::Current + include Controllers::Nonprofit::Authorization + before_action :authenticate_nonprofit_user! - # Gets the nonprofits supporters - # If not logged in, causes a 401 error - def index - @supporters = current_nonprofit.supporters.order('id DESC').page(params[:page]).per(params[:per]) - end + # Gets the nonprofits supporters + # If not logged in, causes a 401 error + def index + @supporters = current_nonprofit.supporters.order("id DESC").page(params[:page]).per(params[:per]) + end - # Gets the a single nonprofit supporter - # If not logged in, causes a 401 error - def show - @supporter = current_nonprofit.supporters.find_by(houid:params[:id]) - end - end + # Gets the a single nonprofit supporter + # If not logged in, causes a 401 error + def show + @supporter = current_nonprofit.supporters.find_by(houid: params[:id]) + end + end end diff --git a/app/controllers/api_new/transactions_controller.rb b/app/controllers/api_new/transactions_controller.rb index 4579cfa5f..beb72e75e 100644 --- a/app/controllers/api_new/transactions_controller.rb +++ b/app/controllers/api_new/transactions_controller.rb @@ -5,21 +5,21 @@ # A controller for interacting with a nonprofit's supporters class ApiNew::TransactionsController < ApiNew::ApiController - include Controllers::ApiNew::Transaction::Current - include Controllers::Nonprofit::Authorization - before_action :authenticate_nonprofit_user! + include Controllers::ApiNew::Transaction::Current + include Controllers::Nonprofit::Authorization + before_action :authenticate_nonprofit_user! - # Gets the nonprofits supporters - # If not logged in, causes a 401 error - def index - set_json_expansion_paths('supporter', 'subtransaction.payments', 'transaction_assignments', 'payments') - @transactions = current_nonprofit.transactions.order('updated_at DESC').page(params[:page]).per(params[:per]) - end + # Gets the nonprofits supporters + # If not logged in, causes a 401 error + def index + set_json_expansion_paths("supporter", "subtransaction.payments", "transaction_assignments", "payments") + @transactions = current_nonprofit.transactions.order("updated_at DESC").page(params[:page]).per(params[:per]) + end - # Gets the a single nonprofit supporter - # If not logged in, causes a 401 error - def show - set_json_expansion_paths('supporter', 'subtransaction.payments', 'transaction_assignments', 'payments') - @transaction = current_transaction - end -end \ No newline at end of file + # Gets the a single nonprofit supporter + # If not logged in, causes a 401 error + def show + set_json_expansion_paths("supporter", "subtransaction.payments", "transaction_assignments", "payments") + @transaction = current_transaction + end +end diff --git a/app/controllers/api_new/users_controller.rb b/app/controllers/api_new/users_controller.rb index 4e84134d5..01a3d0e67 100644 --- a/app/controllers/api_new/users_controller.rb +++ b/app/controllers/api_new/users_controller.rb @@ -3,23 +3,23 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class ApiNew::UsersController < ApiNew::ApiController - include Controllers::User::Authorization + include Controllers::User::Authorization - before_action :authenticate_user! + before_action :authenticate_user! - # Returns the current user as JSON - # If not logged in, causes a 401 error - def current - @user = current_user - end + # Returns the current user as JSON + # If not logged in, causes a 401 error + def current + @user = current_user + end - # get /api_new/users/current_nonprofit_object_events - def current_nonprofit_object_events - np_houid = current_user.roles.where(host_type: 'Nonprofit').first&.host&.houid - if np_houid - redirect_to api_new_nonprofit_object_events_path(np_houid, request.query_parameters) - else - render body: 'Not Found', :status => :not_found - end - end + # get /api_new/users/current_nonprofit_object_events + def current_nonprofit_object_events + np_houid = current_user.roles.where(host_type: "Nonprofit").first&.host&.houid + if np_houid + redirect_to api_new_nonprofit_object_events_path(np_houid, request.query_parameters) + else + render body: "Not Found", status: :not_found + end + end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3556392ce..d0ce38751 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,42 +1,42 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ApplicationController < ActionController::Base - before_action :set_locale, :redirect_to_maintenance - - protect_from_forgery with: :exception - - helper_method \ - :current_role?, - :current_nonprofit_user?, - :administered_nonprofit - - def set_locale - if params[:locale] && Settings.available_locales.include?(params[:locale]) - I18n.locale = params[:locale] - else - I18n.locale = Settings.language - end - end - - def redirect_to_maintenance - if (Settings&.maintenance&.maintenance_mode && !current_user) - unless (self.class == Users::SessionsController && - ((Settings.maintenance.maintenance_token && params[:maintenance_token] == Settings.maintenance.maintenance_token) || params[:format] == 'json')) - redirect_to Settings.maintenance.maintenance_page, - allow_other_host: true - end - end - end - -protected - - def json_saved(model, msg=nil) - if model.valid? - flash[:notice] = msg if msg - render json: model, status: 200 - else - render json: model.errors.full_messages, status: :unprocessable_entity - end - end + before_action :set_locale, :redirect_to_maintenance + + protect_from_forgery with: :exception + + helper_method \ + :current_role?, + :current_nonprofit_user?, + :administered_nonprofit + + def set_locale + I18n.locale = if params[:locale] && Settings.available_locales.include?(params[:locale]) + params[:locale] + else + Settings.language + end + end + + def redirect_to_maintenance + if Settings&.maintenance&.maintenance_mode && !current_user + unless self.class == Users::SessionsController && + ((Settings.maintenance.maintenance_token && params[:maintenance_token] == Settings.maintenance.maintenance_token) || params[:format] == "json") + redirect_to Settings.maintenance.maintenance_page, + allow_other_host: true + end + end + end + + protected + + def json_saved(model, msg = nil) + if model.valid? + flash[:notice] = msg if msg + render json: model, status: 200 + else + render json: model.errors.full_messages, status: :unprocessable_entity + end + end # A response helper for use with the param_validation gem # use like: render_json{ UpdateUsers.update(params[:user]) } @@ -46,120 +46,117 @@ def render_json(&block) result = {status: 200, json: yield(block)} rescue ParamValidation::ValidationError => e logger.info "422: #{e}".red.bold - #logger.info ">>".bold.red + " #{{'Failed key name' => e.data[:key], 'Value' => e.data[:val], 'Failed validator' => e.data[:name]}}".red + # logger.info ">>".bold.red + " #{{'Failed key name' => e.data[:key], 'Value' => e.data[:val], 'Failed validator' => e.data[:name]}}".red + result = {status: 422, json: {error: e.message}} + rescue HoudiniError => e + logger.info "422: #{e}".red.bold result = {status: 422, json: {error: e.message}} - rescue HoudiniError => e - logger.info "422: #{e}".red.bold - result = {status: 422, json: {error: e.message}} rescue ActiveRecord::RecordNotFound => e logger.info "404: #{e}".red.bold result = {status: 404, json: {error: e.message}} - rescue AuthenticationError => e - logger.info "401: #{e}".red.bold - result = {status: 401, json: {error: e.message}} - rescue ExpiredTokenError => e - logger.info "422: #{e}".red.bold - result = {status: 422, json: {error: e.message}} + rescue AuthenticationError => e + logger.info "401: #{e}".red.bold + result = {status: 401, json: {error: e.message}} + rescue ExpiredTokenError => e + logger.info "422: #{e}".red.bold + result = {status: 422, json: {error: e.message}} rescue Exception => e # a non-validation related exception logger.error "500: #{e}".red.bold - logger.error e.backtrace.take(5).map{|l| ">>".red.bold + " #{l}"}.join("\n").red + logger.error e.backtrace.take(5).map { |l| ">>".red.bold + " #{l}" }.join("\n").red result = {status: 500, json: {error: e.message, backtrace: e.backtrace}} end render result end - # Test that within the last 5 minutes, the user has confirmed their password - def password_was_confirmed(token) - session[:pw_token] == token && Chronic.parse(session[:pw_timestamp]) >= 5.minutes.ago.utc - end + # Test that within the last 5 minutes, the user has confirmed their password + def password_was_confirmed(token) + session[:pw_token] == token && Chronic.parse(session[:pw_timestamp]) >= 5.minutes.ago.utc + end - def store_location - referrer = request.fullpath - no_redirects = ['/users', '/signup', '/signin', '/users/sign_in', '/users/sign_up', '/users/password', '/users/sign_out', /.*\.json.*/, /.*auth\/facebook.*/] - unless request.format.symbol == :json || no_redirects.map{|p| referrer.match(p)}.any? - session[:previous_url] = referrer - end - end + def store_location + referrer = request.fullpath + no_redirects = ["/users", "/signup", "/signin", "/users/sign_in", "/users/sign_up", "/users/password", "/users/sign_out", /.*\.json.*/, /.*auth\/facebook.*/] + unless request.format.symbol == :json || no_redirects.map { |p| referrer.match(p) }.any? + session[:previous_url] = referrer + end + end - def block_with_sign_in(msg=nil) - store_location + def block_with_sign_in(msg = nil) + store_location if current_user flash[:notice] = "It looks like you're not allowed to access that page. If this seems like a mistake, please contact #{Settings.mailer.email}" redirect_to root_path else - msg ||= 'We need to sign you in before you can do that.' - redirect_to new_user_session_path, :flash => {:error => msg} + msg ||= "We need to sign you in before you can do that." + redirect_to new_user_session_path, flash: {error: msg} end - end - - def authenticate_user!(options={}) - block_with_sign_in unless current_user - end - - def authenticate_confirmed_user! - if !current_user - block_with_sign_in - elsif !current_user.confirmed? && !current_role?([:super_associate, :super_admin]) - redirect_to new_user_confirmation_path, flash: {error: 'You need to confirm your account to do that.'} - end - end - - def authenticate_super_associate! - unless current_role?(:super_admin) || current_role?(:super_associate) - block_with_sign_in 'Please login.' - end - end - - def authenticate_super_admin! - unless current_role?(:super_admin) - block_with_sign_in 'Please login.' - end - end - - def current_role?(role_names, host_id = nil) + end + + def authenticate_user!(options = {}) + block_with_sign_in unless current_user + end + + def authenticate_confirmed_user! + if !current_user + block_with_sign_in + elsif !current_user.confirmed? && !current_role?([:super_associate, :super_admin]) + redirect_to new_user_confirmation_path, flash: {error: "You need to confirm your account to do that."} + end + end + + def authenticate_super_associate! + unless current_role?(:super_admin) || current_role?(:super_associate) + block_with_sign_in "Please login." + end + end + + def authenticate_super_admin! + unless current_role?(:super_admin) + block_with_sign_in "Please login." + end + end + + def current_role?(role_names, host_id = nil) return false unless current_user role_names = Array(role_names) - key = "current_role_user_#{current_user_id}_names_#{role_names.join("_")}_host_#{host_id}" QueryRoles.user_has_role?(current_user.id, role_names, host_id) - end + end - def administered_nonprofit - return nil unless current_user - key = "administered_nonprofit_user_#{current_user_id}_nonprofit" + def administered_nonprofit + return nil unless current_user Nonprofit.where(id: QueryRoles.host_ids(current_user_id, [:nonprofit_admin, :nonprofit_associate])).last - end + end - # devise config + # devise config - def after_sign_in_path_for(resource) - request.env['omniauth.origin'] || session[:previous_url] || root_path - end + def after_sign_in_path_for(resource) + request.env["omniauth.origin"] || session[:previous_url] || root_path + end - def after_sign_up_path_for(resource) - request.env['omniauth.origin'] || session[:previous_url] || root_path - end + def after_sign_up_path_for(resource) + request.env["omniauth.origin"] || session[:previous_url] || root_path + end - def after_update_path_for(resource) - profile_path(current_user.profile) - end + def after_update_path_for(resource) + profile_path(current_user.profile) + end - def after_inactive_sign_up_path_for(resource) - profile_path(current_user.profile) - end + def after_inactive_sign_up_path_for(resource) + profile_path(current_user.profile) + end - # /devise config + # /devise config -private + private - def current_user_id - current_user && current_user.id - end + def current_user_id + current_user && current_user.id + end - # Overload handle_unverified_request to ensure that + # Overload handle_unverified_request to ensure that # exception is raised each time a request does not # pass validation. def handle_unverified_request - Airbrake.notify(ActionController::InvalidAuthenticityToken, params: params) - + Airbrake.notify(ActionController::InvalidAuthenticityToken, params: params) end end diff --git a/app/controllers/aws_presigned_posts_controller.rb b/app/controllers/aws_presigned_posts_controller.rb index c35ae2d23..cf62b9d20 100644 --- a/app/controllers/aws_presigned_posts_controller.rb +++ b/app/controllers/aws_presigned_posts_controller.rb @@ -10,7 +10,7 @@ def create p = S3Bucket.presigned_post({ key: "tmp/#{uuid}/${filename}", success_action_status: "201", - acl: 'public-read', + acl: "public-read", expires: 30.days.from_now }) @@ -20,5 +20,4 @@ def create s3_uuid: uuid } end - end diff --git a/app/controllers/billing_subscriptions_controller.rb b/app/controllers/billing_subscriptions_controller.rb index dc9e1af0f..77d6857c7 100644 --- a/app/controllers/billing_subscriptions_controller.rb +++ b/app/controllers/billing_subscriptions_controller.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class BillingSubscriptionsController < ApplicationController - include Controllers::NonprofitHelper + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_admin! + before_action :authenticate_nonprofit_admin! # post /nonprofits/:nonprofit_id/billing_subscription/cancel - def cancel - @result = CancelBillingSubscription.with_stripe(@nonprofit) - flash[:notice] = "Your subscription has been cancelled. We'll email you soon with exports." + def cancel + @result = CancelBillingSubscription.with_stripe(@nonprofit) + flash[:notice] = "Your subscription has been cancelled. We'll email you soon with exports." redirect_to root_url - end + end # get nonprofits/:nonprofit_id/billing_subscription/cancellation def cancellation diff --git a/app/controllers/button_debug_controller.rb b/app/controllers/button_debug_controller.rb index 9194b0a89..e829c6a46 100644 --- a/app/controllers/button_debug_controller.rb +++ b/app/controllers/button_debug_controller.rb @@ -2,11 +2,11 @@ class ButtonDebugController < ApplicationController def embedded @np = params[:id] || 1 - respond_to { |format| format.html{render layout: 'layouts/empty'} } + respond_to { |format| format.html { render layout: "layouts/empty" } } end def button @np = params[:id] || 1 - respond_to { |format| format.html{render layout: 'layouts/empty'} } + respond_to { |format| format.html { render layout: "layouts/empty" } } end end diff --git a/app/controllers/campaign_gift_options_controller.rb b/app/controllers/campaign_gift_options_controller.rb index 044aab0b2..3fd18da06 100644 --- a/app/controllers/campaign_gift_options_controller.rb +++ b/app/controllers/campaign_gift_options_controller.rb @@ -1,40 +1,40 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignGiftOptionsController < ApplicationController - include Controllers::CampaignHelper + include Controllers::CampaignHelper - before_action :authenticate_campaign_editor!, only: [:create, :destroy, :update, :update_order] + before_action :authenticate_campaign_editor!, only: [:create, :destroy, :update, :update_order] - def index - @gift_options = current_campaign.campaign_gift_options.order('"order", amount_recurring, amount_one_time') - render json: {data: @gift_options} - end + def index + @gift_options = current_campaign.campaign_gift_options.order('"order", amount_recurring, amount_one_time') + render json: {data: @gift_options} + end - def show - render json: {data: current_campaign.campaign_gift_options.find(params[:id])} - end + def show + render json: {data: current_campaign.campaign_gift_options.find(params[:id])} + end - def create - campaign = current_campaign - json_saved CreateCampaignGiftOption.create(campaign, params[:campaign_gift_option]), - 'Gift option successfully created!' - end + def create + campaign = current_campaign + json_saved CreateCampaignGiftOption.create(campaign, params[:campaign_gift_option]), + "Gift option successfully created!" + end - def update - @campaign = current_campaign - gift_option = @campaign.campaign_gift_options.find params[:id] - json_saved UpdateCampaignGiftOption.update(gift_option, params[:campaign_gift_option]), 'Successfully updated' - end + def update + @campaign = current_campaign + gift_option = @campaign.campaign_gift_options.find params[:id] + json_saved UpdateCampaignGiftOption.update(gift_option, params[:campaign_gift_option]), "Successfully updated" + end # put /nonprofits/:nonprofit_id/campaigns/:campaign_id/campaign_gift_options/update_order # Pass in {data: [{id: 1, order: 1}]} def update_order - updated_gift_options = UpdateOrder.with_data('campaign_gift_options', params[:data]) + updated_gift_options = UpdateOrder.with_data("campaign_gift_options", params[:data]) render json: updated_gift_options end - def destroy - @campaign = current_campaign + def destroy + @campaign = current_campaign - render_json { DeleteCampaignGiftOption.delete(@campaign, params[:id])} - end + render_json { DeleteCampaignGiftOption.delete(@campaign, params[:id]) } + end end diff --git a/app/controllers/campaign_gifts_controller.rb b/app/controllers/campaign_gifts_controller.rb index 786173ff3..81405dcc8 100644 --- a/app/controllers/campaign_gifts_controller.rb +++ b/app/controllers/campaign_gifts_controller.rb @@ -1,8 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignGiftsController < ApplicationController - # post /campaign_gifts - def create - json_saved CreateCampaignGift.create params[:campaign_gift] - end + def create + json_saved CreateCampaignGift.create params[:campaign_gift] + end end diff --git a/app/controllers/campaigns/campaign_gift_options_controller.rb b/app/controllers/campaigns/campaign_gift_options_controller.rb index a3a8e88a5..0989509a0 100644 --- a/app/controllers/campaigns/campaign_gift_options_controller.rb +++ b/app/controllers/campaigns/campaign_gift_options_controller.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Campaigns::CampaignGiftOptionsController < ApplicationController - include Controllers::CampaignHelper + include Controllers::CampaignHelper - before_action :authenticate_campaign_editor!, only: [:index] - - def index - respond_to do |format| - format.json do - render json: QueryCampaignGifts.report_metrics(current_campaign.id) - end - end - end + before_action :authenticate_campaign_editor!, only: [:index] + def index + respond_to do |format| + format.json do + render json: QueryCampaignGifts.report_metrics(current_campaign.id) + end + end + end end diff --git a/app/controllers/campaigns/donations_controller.rb b/app/controllers/campaigns/donations_controller.rb index a53c0f3db..beb20ebdf 100644 --- a/app/controllers/campaigns/donations_controller.rb +++ b/app/controllers/campaigns/donations_controller.rb @@ -1,19 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Campaigns -class DonationsController < ApplicationController - include Controllers::CampaignHelper + class DonationsController < ApplicationController + include Controllers::CampaignHelper - before_action :authenticate_campaign_editor!, only: [:index] + before_action :authenticate_campaign_editor!, only: [:index] - def index - respond_to do |format| - format.csv do - file_date = Date.today.strftime("%m-%d-%Y") - donations = QueryDonations.campaign_export(current_campaign.id) - send_data(Format::Csv.from_vectors(donations), filename: "campaign-donations-#{file_date}.csv") - end - end - end - -end + def index + respond_to do |format| + format.csv do + file_date = Date.today.strftime("%m-%d-%Y") + donations = QueryDonations.campaign_export(current_campaign.id) + send_data(Format::Csv.from_vectors(donations), filename: "campaign-donations-#{file_date}.csv") + end + end + end + end end diff --git a/app/controllers/campaigns/supporters_controller.rb b/app/controllers/campaigns/supporters_controller.rb index 5f77ffd06..d505a9fe7 100644 --- a/app/controllers/campaigns/supporters_controller.rb +++ b/app/controllers/campaigns/supporters_controller.rb @@ -1,22 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Campaigns -class SupportersController < ApplicationController - include Controllers::CampaignHelper + class SupportersController < ApplicationController + include Controllers::CampaignHelper - before_action :authenticate_campaign_editor!, only: [:index] + before_action :authenticate_campaign_editor!, only: [:index] - def index - @panels_layout = true - @nonprofit = current_nonprofit - @campaign = current_campaign + def index + @panels_layout = true + @nonprofit = current_nonprofit + @campaign = current_campaign - respond_to do |format| - format.json do - render json: QuerySupporters.campaign_list(@nonprofit.id, @campaign.id, params) - end - format.html - end - end - -end + respond_to do |format| + format.json do + render json: QuerySupporters.campaign_list(@nonprofit.id, @campaign.id, params) + end + format.html + end + end + end end diff --git a/app/controllers/campaigns_controller.rb b/app/controllers/campaigns_controller.rb index 6edd58306..7126b5e22 100644 --- a/app/controllers/campaigns_controller.rb +++ b/app/controllers/campaigns_controller.rb @@ -10,12 +10,12 @@ class CampaignsController < ApplicationController def index @nonprofit = current_nonprofit - if (current_nonprofit_user?) - @campaigns = @nonprofit.campaigns.includes(:nonprofit).not_deleted.order('created_at desc') - @deleted_campaigns = @nonprofit.campaigns.includes(:nonprofit).deleted.order('created_at desc') + if current_nonprofit_user? + @campaigns = @nonprofit.campaigns.includes(:nonprofit).not_deleted.order("created_at desc") + @deleted_campaigns = @nonprofit.campaigns.includes(:nonprofit).deleted.order("created_at desc") else - @campaigns = @nonprofit.campaigns.includes(:nonprofit).not_deleted.not_a_child.order('created_at desc') - @deleted_campaigns = @nonprofit.campaigns.includes(:nonprofit).deleted.not_a_child.order('created_at desc') + @campaigns = @nonprofit.campaigns.includes(:nonprofit).not_deleted.not_a_child.order("created_at desc") + @deleted_campaigns = @nonprofit.campaigns.includes(:nonprofit).deleted.not_a_child.order("created_at desc") end respond_to do |format| @@ -58,13 +58,13 @@ def activities end def create - Time.use_zone(current_nonprofit.timezone || 'UTC') do + Time.use_zone(current_nonprofit.timezone || "UTC") do params[:campaign][:end_datetime] = Chronic.parse(params[:campaign][:end_datetime]) if params[:campaign][:end_datetime].present? end if !params[:campaign][:parent_campaign_id] campaign = current_nonprofit.campaigns.create params[:campaign] - json_saved campaign, 'Campaign created! Well done.' + json_saved campaign, "Campaign created! Well done." else profile_id = params[:campaign][:profile_id] Profile.find(profile_id).update_attributes params[:profile] @@ -73,24 +73,21 @@ def create end def update - Time.use_zone(current_nonprofit.timezone || 'UTC') do + Time.use_zone(current_nonprofit.timezone || "UTC") do params[:campaign][:end_datetime] = Chronic.parse(params[:campaign][:end_datetime]) if params[:campaign][:end_datetime].present? end current_campaign.update_attributes params[:campaign] - json_saved current_campaign, 'Successfully updated!' + json_saved current_campaign, "Successfully updated!" end # post 'nonprofits/:np_id/campaigns/:campaign_id/duplicate' def duplicate - render_json { InsertDuplicate.campaign(current_campaign.id, current_user.profile.id) } - end - def soft_delete current_campaign.update_attribute(:deleted, params[:delete]) render json: {} @@ -119,12 +116,12 @@ def peer_to_peer @parent_campaign = Campaign.find_by_id(params[:campaign_id]) if params[:campaign_id].present? && !@parent_campaign - raise ActionController::RoutingError.new('Not Found') + raise ActionController::RoutingError.new("Not Found") end if current_user @profile = current_user.profile - if (@parent_campaign) + if @parent_campaign @child_campaign = Campaign.where( profile_id: @profile.id, parent_campaign_id: @parent_campaign.id @@ -137,12 +134,12 @@ def peer_to_peer def check_nonprofit_status if !current_role?(:super_admin) && !current_nonprofit.published - raise ActionController::RoutingError.new('Not Found') + raise ActionController::RoutingError.new("Not Found") end end def set_access_control_headers - headers['Access-Control-Allow-Origin'] = "*" - headers['Access-Control-Request-Method'] = %w{GET}.join(",") + headers["Access-Control-Allow-Origin"] = "*" + headers["Access-Control-Request-Method"] = %w[GET].join(",") end end diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb index fa75ca58f..536ebc584 100755 --- a/app/controllers/cards_controller.rb +++ b/app/controllers/cards_controller.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CardsController < ApplicationController - - before_action :authenticate_user!, :except => [:create] + before_action :authenticate_user!, except: [:create] before_action :verify_via_recaptcha!, only: [:create] before_action :validate_allowed!, only: [:create] @@ -9,49 +8,48 @@ class CardsController < ApplicationController rescue_from ::TempBlockError, with: :handle_temp_block_error - # post /cards + # post /cards def create render( JsonResp.new(params) do |d| requires(:card).nested do requires(:name, :stripe_card_token).as_string requires(:holder_id).as_int - requires(:holder_type).one_of('Supporter') + requires(:holder_type).one_of("Supporter") end end.when_valid do |d| supporter = Supporter.find(d[:card][:holder_id]) acct = supporter.nonprofit.stripe_account_id - InsertCard.with_stripe(d[:card], acct, params[:event_id], current_user) + InsertCard.with_stripe(d[:card], acct, params[:event_id], current_user) end ) - end + end private + def verify_via_recaptcha! - begin - verify_recaptcha!(action: 'create_card', minimum_score: ENV['MINIMUM_RECAPTCHA_SCORE'].to_f) - rescue ::Recaptcha::RecaptchaError => e - supporter_id = params.try(:card).try(:holder_id) - failure_details = { - supporter: supporter_id, - params: params, - action: 'create_card', - minimum_score_required: ENV['MINIMUM_RECAPTCHA_SCORE'], - recaptcha_result: recaptcha_reply, - recaptcha_value: params['g-recaptcha-response'] - } - failure = RecaptchaRejection.new - failure.details = failure_details - failure.save! - raise e - end + verify_recaptcha!(action: "create_card", minimum_score: ENV["MINIMUM_RECAPTCHA_SCORE"].to_f) + rescue ::Recaptcha::RecaptchaError => e + supporter_id = params.try(:card).try(:holder_id) + failure_details = { + supporter: supporter_id, + params: params, + action: "create_card", + minimum_score_required: ENV["MINIMUM_RECAPTCHA_SCORE"], + recaptcha_result: recaptcha_reply, + recaptcha_value: params["g-recaptcha-response"] + } + failure = RecaptchaRejection.new + failure.details = failure_details + failure.save! + raise e end def handle_recaptcha_failure render json: {error: "There was an temporary error preventing your payment. Please try again. If it persists, please contact support@commitchange.com with error code: 5X4J "}, status: :unprocessable_entity end - def handle_temp_block_error + def handle_temp_block_error render json: {error: "no"}, status: :unprocessable_entity end @@ -62,5 +60,5 @@ def validate_allowed! raise TempBlockError end end - end + end end diff --git a/app/controllers/concerns/controllers/api_new/jbuilder_expansions.rb b/app/controllers/concerns/controllers/api_new/jbuilder_expansions.rb index cafd4dd93..c6ec0f1a9 100644 --- a/app/controllers/concerns/controllers/api_new/jbuilder_expansions.rb +++ b/app/controllers/concerns/controllers/api_new/jbuilder_expansions.rb @@ -3,433 +3,423 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -=begin - -This concern simplifies creating JBuilder objects. - +# +# This concern simplifies creating JBuilder objects. +# ## The format for child objects in Houdini API - -Child objects for attributes for the Houdini API follow a format based upon the Stripe API -When a child is not expanded it will consist only of the Houid -For example consider in the following object, child is not expanded: -```json -{ - child: "chd_21n45ho...", - id: "familyobj_4532154ni" -} -``` - -However when a child is expanded it will look like this: - -```json -{ - child: { - id: "chd_21n45ho...", - additional_attribute: 1, - parent: "prt_352159", - subchildren: ["subchd_235n158...", "subchd_203213598..."] - }, - id: "familyobj_4532154ni" -} -``` - +# +# Child objects for attributes for the Houdini API follow a format based upon the Stripe API +# When a child is not expanded it will consist only of the Houid +# For example consider in the following object, child is not expanded: +# ```json +# { +# child: "chd_21n45ho...", +# id: "familyobj_4532154ni" +# } +# ``` +# +# However when a child is expanded it will look like this: +# +# ```json +# { +# child: { +# id: "chd_21n45ho...", +# additional_attribute: 1, +# parent: "prt_352159", +# subchildren: ["subchd_235n158...", "subchd_203213598..."] +# }, +# id: "familyobj_4532154ni" +# } +# ``` +# ### JSON Simplified Path (SPath) -a JSON Simplified Path (SPath) is a bit like dot object notation for JSON objects. For example -If you wanted to reference the child attribute above, you would use the very simple spath of -`child` - -If you wanted to reference the child's id attribute, you would use `child.id` - -One characteristic of SPaths is how they handle arrays. If an spath references an array, it's -actually referencing every item in the array. This will matter later in this code. - -###Combining SPaths and expansion -Now that have SPaths you may be wondering how this relates to expandable attributes. Based upon some input, -we may want decided at runtime whether expand an attribute when rendering Jbuilder templates SPaths allow us to define which items are expanded. To do so, -we go to our Controller action and provide the SPaths of which attributes we want expanded in the outputted object. We do this by passing the -the SPaths to the `set_json_expansion_paths` method. So, if we want to expand the `child` from above, we would call: -`set_json_expansion_paths('child')` - ```json -{ - child: { - id: "chd_21n45ho...", - additional_attribute: 1, - parent: { - id: "prt_352159" - some_other_attribute: "attrib to remember" - }, - subchildren: ["subchd_235n158...", "subchd_203213598..."] - }, - id: "familyobj_4532154ni" -} -``` - -What if we want to expand the parent attribute inside child? We can pass the SPath as follows:`set_json_expansion_paths('child.parent')`. And we get the following: - -Notice that we -don't have to pass child separately. Our expansions know to expand everything back to the root of our Jbuilder value. Your could pass `set_json_expansion_paths('child', 'child.parent')` - -What happens for arrays? We can pass the SPath for subchildren using the same notation `set_json_expansion_paths('child.subchildren')`: - -```json -{ - child: { - id: "chd_21n45ho...", - additional_attribute: 1, - parent: "prt_352159", - subchildren: [ - { - id: "subchd_235n158...", - value: 22942190 - }, - { - id: "subchd_203213598...", - value: 312539 - } - ] - }, - id: "familyobj_4532154ni" -} -``` - -###Expansion and partials -You may be wondering how we know what to generate when we ask for an object to be expanded. We use a feature of JBuidler -where, which selects the partial based upon the class of the object passed to `partial!`. For example, -if you call `json.partial! object` and object is of type Parent, Jbuilder knows that you want to use the partial at `app/views/parents/_parent.json.jbuilder`. - +# a JSON Simplified Path (SPath) is a bit like dot object notation for JSON objects. For example +# If you wanted to reference the child attribute above, you would use the very simple spath of +# `child` +# +# If you wanted to reference the child's id attribute, you would use `child.id` +# +# One characteristic of SPaths is how they handle arrays. If an spath references an array, it's +# actually referencing every item in the array. This will matter later in this code. +# +# ##Combining SPaths and expansion +# Now that have SPaths you may be wondering how this relates to expandable attributes. Based upon some input, +# we may want decided at runtime whether expand an attribute when rendering Jbuilder templates SPaths allow us to define which items are expanded. To do so, +# we go to our Controller action and provide the SPaths of which attributes we want expanded in the outputted object. We do this by passing the +# the SPaths to the `set_json_expansion_paths` method. So, if we want to expand the `child` from above, we would call: +# `set_json_expansion_paths('child')` +# ```json +# { +# child: { +# id: "chd_21n45ho...", +# additional_attribute: 1, +# parent: { +# id: "prt_352159" +# some_other_attribute: "attrib to remember" +# }, +# subchildren: ["subchd_235n158...", "subchd_203213598..."] +# }, +# id: "familyobj_4532154ni" +# } +# ``` +# +# What if we want to expand the parent attribute inside child? We can pass the SPath as follows:`set_json_expansion_paths('child.parent')`. And we get the following: +# +# Notice that we +# don't have to pass child separately. Our expansions know to expand everything back to the root of our Jbuilder value. Your could pass `set_json_expansion_paths('child', 'child.parent')` +# +# What happens for arrays? We can pass the SPath for subchildren using the same notation `set_json_expansion_paths('child.subchildren')`: +# +# ```json +# { +# child: { +# id: "chd_21n45ho...", +# additional_attribute: 1, +# parent: "prt_352159", +# subchildren: [ +# { +# id: "subchd_235n158...", +# value: 22942190 +# }, +# { +# id: "subchd_203213598...", +# value: 312539 +# } +# ] +# }, +# id: "familyobj_4532154ni" +# } +# ``` +# +# ##Expansion and partials +# You may be wondering how we know what to generate when we ask for an object to be expanded. We use a feature of JBuidler +# where, which selects the partial based upon the class of the object passed to `partial!`. For example, +# if you call `json.partial! object` and object is of type Parent, Jbuilder knows that you want to use the partial at `app/views/parents/_parent.json.jbuilder`. +# ### How to use this all in practice on a controller action -Using this in practice requires a few steps but is honestly pretty straightforward. - +# Using this in practice requires a few steps but is honestly pretty straightforward. +# #### 1. Make sure there is a #to_houid method on the object -Remember, for an object to be shrunk, we need to be able to output the value #to_houid. So we need that for any object which could be expanded. - +# Remember, for an object to be shrunk, we need to be able to output the value #to_houid. So we need that for any object which could be expanded. +# #### 2. Make sure to call `#set_json_expansion_paths` in your action with the SPaths you want to expand. - -In your controller action, you need to set which SPaths you want to expand. You can set these based upon parameters passed in (you may want to limit the depth however) -or simply have a default value. - -```ruby +# +# In your controller action, you need to set which SPaths you want to expand. You can set these based upon parameters passed in (you may want to limit the depth however) +# or simply have a default value. +# +# ```ruby # in `app/controllers/family_objects_controller.rb` -class FamilyObjectsController < ApplicationController - include Controllers::ApiNew::JbuilderExpansions - - def show - set_json_expansion_paths('child') # we just want to expand the child attribute - @family_object = FamilyObject.find(.........) # assume you get the family object you want here - end -end -```` - +# class FamilyObjectsController < ApplicationController +# include Controllers::ApiNew::JbuilderExpansions +# +# def show +# set_json_expansion_paths('child') # we just want to expand the child attribute +# @family_object = FamilyObject.find(.........) # assume you get the family object you want here +# end +# end +# ```` +# #### 3. In your JBuilder view template for the show action make sure to add `__expand: @expand` to the end of your render partial call - -```ruby +# +# ```ruby # in `app/views/family_objects/show.json.jbuilder` -json.partial! @family_object, as: :family_object, __expand: @__expand -``` - +# json.partial! @family_object, as: :family_object, __expand: @__expand +# ``` +# #### 4. Starting at the partial called in your show template, add `#handle_expansion` and `#handle_array_expansion` calls - -```ruby +# +# ```ruby # in `app/views/family_objects/_family_object.json.jbuilder` - -json.id family_object.to_houid - -handle_expansion(:child, family_object, {json: json, __expand: __expand}) # make sure json and __expand are there! -``` - +# +# json.id family_object.to_houid +# +# handle_expansion(:child, family_object, {json: json, __expand: __expand}) # make sure json and __expand are there! +# ``` +# #### 5. Continue adding expansion calls in any partials referred to by the initial partial or any partials it references recursively - -```ruby +# +# ```ruby # in `app/views/children/_child.json.jbuilder` -json.id child.to_houid - -json.(child, :additional_attribute) - -handle_expansion(:parent, child, {json: json, __expand: __expand}) # make sure json and __expand are there! - -handle_array_expansion(:subchildren, child, {as: :child, json: json, __expand: __expand}) # We're assuming each of subchildren is actually a Child object - # make sure json and __expand are there! - -``` - -```ruby +# json.id child.to_houid +# +# json.(child, :additional_attribute) +# +# handle_expansion(:parent, child, {json: json, __expand: __expand}) # make sure json and __expand are there! +# +# handle_array_expansion(:subchildren, child, {as: :child, json: json, __expand: __expand}) # We're assuming each of subchildren is actually a Child object +# # make sure json and __expand are there! +# +# ``` +# +# ```ruby # in `app/views/parents/_parent.json.jbuilder` -json.id parent.to_houid - -json.some_other_attribute parent.some_other_attribute -``` -=end - +# json.id parent.to_houid +# +# json.some_other_attribute parent.some_other_attribute +# ``` module Controllers::ApiNew::JbuilderExpansions - extend ActiveSupport::Concern - included do - - @__expand = Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new - - # The SPaths for the expandable attributes you would like to expand. By default, no attributes are expanded. - # You can call this multiple times and new calls will override any previous calls - def set_json_expansion_paths(*expansions) - @__expand = Controllers::ApiNew::JbuilderExpansions.build_json_expansion_path_tree(*expansions) - end - - # Builds the {ExpansionTree}. This is rarely needed but could be helpful in certain specific cases - # @param [Array,Array] paths the paths to expand. If the first item is a {String} then this is an array of SPaths. If the first item is - # an {ExpansionTree}, this object returns that item - # @return [ExpansionTree] - def build_json_expansion_path_tree(*paths) - Controllers::ApiNew::JbuilderExpansions.build_json_expansion_path_tree(*paths) - end - - # Configures an attribute which can be expanded in an jbuilder template - # When shrunk, if you pass this is the equivalent of writing: - # `json.set! attribute, source&.to_houid` # This assumes you passed the :attribute as the attribute - # When expanded, this is the equivalent of: - # `json.set! attribute do - # json.partial! opts[:object] - # end` - # - # @param [Symbol] attribute the name of the attribute that you would like output. - # @param [any] source an object which with an attribute which can be expanded - # @option opts [JbuilderTemplate] :json the JBuilder object being used to generate the outputted JSON This is required. - # @option opts [ExpansionTree] :__expand the ExpansionTree for this current template. This is required. - # @option opts [Symbol] :as the method we call on 'object' when expanding the node. - def handle_expansion(attribute, source, opts={}) - opts = opts.deep_symbolize_keys - opts[:__expand] ||= __expand - ExpansionTreeVisitor.handle_expansion(attribute, source, opts) - end - - # configures an attribute for an array which can be expanded in a jbuilder template - # - # When shrunk, this is the equivalent of writing: - # ```ruby - # json.set! attribute, source.map{|i| i&.to_houid} - # ```` - # When expanded, with the helper of this is the equivalent of writing: - # ```ruby - # json.(attribute) source do |item| # assumes opts[:as] is the same as "attribute" - # json.partial! item - # end - # @param [Symbol] attribute the name of the attribute that you would like output. - # @param [Enumerable] source an enumerable of objects, each of which has an attribute which can be expanded - # @option opts [JbuilderTemplate] :json the JBuilder object being used to generate the outputted JSON This is required. - # @option opts [ExpansionTree] :__expand the ExpansionTree for this current template. This is required. - # @option opts [Symbol] :as_item the method we call on each of the array items as part of a #handle_array_expansion call. - # @yieldparam [ItemExpansion] item if block is passed, an ItemExpansion will be yielded for each item for in the partial - def handle_array_expansion(attribute, source, opts={}, &block) - opts = opts.deep_symbolize_keys - opts[:__expand] ||= __expand - ExpansionTreeVisitor.handle_array_expansion(attribute, source, opts, &block) - end - - helper_method :handle_expansion, :handle_array_expansion, :build_json_expansion_path_tree - end - - def self.build_json_expansion_path_tree(*paths) - request = ExpansionTree.new - paths = paths.flatten - if paths.count == 1 - if paths.first.is_a? String - request = ExpansionTree.new(*paths) - elsif paths.first.is_a? ExpansionTree - request = paths.first - end - elsif paths.any? - request = ExpansionTree.new(*paths) - end - - request - end - - # Applies Visitor(ish) pattern to an object. One of these is created for every new partial corresponding to a node in the tree - # - # Should not be used directly. - # - # @api private - class ExpansionTreeVisitor - # the attribute to add to the outputted JSON - # @return [Symbol] - attr_reader :attribute - - # the object we're visiting - attr_reader :object - - # @param [Symbol] attribute the attribute in the outputted JSON - # @param [Object,Enumerable] object the object being visited. object is an enumerable, then it's an array - # @option opts [JbuilderTemplate] :json the JBuilder object being used to generate the outputted JSON This is required. - # @option opts [ExpansionTree] :__expand the ExpansionTree for this current template. This is required. - # @option opts [Symbol] :as the method we call on 'object' when expanding the node. - # @option opts [Symbol] :item_as the method we call on each of the array items as part of a #handle_array_expansion call. - def initialize(attribute, object, opts) - @attribute = attribute - @object = object - @opts = opts.deep_symbolize_keys - end - - # the JBuilder object being used to generate the outputted JSON - # @return [JbuilderTemplate] the JBuilder object being used to generate the outputted JSON - def json - @opts[:json] - end - - # the ExpansionTree for the current partial - # @return [ExpansionTree] the tree for the current partial - def exp_request - @opts[:__expand] - end - - # the method we call on 'object' when expanding the node. Defaults to #attribute - # @return [Symbol] - def as - @opts[:as] || attribute - end - - # the method we call on each of the array items when expanding the node as part of a #handle_array_expansion call. Defaults to #attribute - # @return [Symbol] - def item_as - @opts[:item_as] || attribute - end - - def visit_expansion - if object.nil? - json.set! attribute, nil - else - if exp_request.expand? attribute - json.set! attribute do - json.partial! object, as: as, __expand: exp_request[attribute] - end - else - json.set! attribute, object&.to_houid - end - end - end - - # If #attribute is not set to expand then create an array of houids from the item in #object like: - # - # `json.friends ['friend_3254n132', 'friend_1245']` - # - # If #attribute is set to expand then create an array with the objects associated with the items. Alternatively, you - # can pass a block and this will yield an {ItemExpansion} so you can do your own manipulation of the specific item. - def visit_array_expansion - json.set! attribute do - if !exp_request.expand? attribute - json.array! object.map(&:to_houid) - else - object.each do |item| - json.child! do - if block_given? - yield(ItemExpansion.new(item, item_as, {json: json, __expand: exp_request[attribute]})) - else - ItemExpansion.new(item, item_as, {json: json, __expand: exp_request[attribute]}).handle_item_expansion - end - end - end - end - end - end - - def visit_item_expansion - json.partial! object, as: as, __expand: exp_request - end - - def self.handle_expansion(attribute, object, opts) - ExpansionTreeVisitor.new(attribute, object, opts).visit_expansion - end - - def self.handle_array_expansion(attribute, object, opts, &block) - ExpansionTreeVisitor.new(attribute, object, opts).visit_array_expansion(&block) - end - end - - class ItemExpansion - attr_reader :item, :as - - - def initialize(item, as, opts={}) - @item = item - @as = as - @json = opts[:json] - @__expand = opts[:__expand] - end - - def handle_item_expansion(object=nil) - if object.nil? - object = item - end - ExpansionTreeVisitor.new(nil, object, {as: as, json: @json, __expand: @__expand}).visit_item_expansion - end - end - - # an ExpansionTree takes a list of JSON SPath and then generates a tree for calculating what should be expanded - # To help understand why this a tree, consider the following SPaths: `supporter`, `nonprofit`, `nonprofit.user`. - # One could describe the SPath expansions as follows: - # - # ```ruby - # (root) - # | - # |---supporter - # | - # |---nonprofit - # | - # |--- user - # ``` - # - # @note You shouldn't be using the details of this class directly, you'll just be passing the object around - # as part of the various expansion requests - # @api private - class ExpansionTree - attr_accessor :root_node - - # @param [Array] paths the JSON SPaths for this tree - def initialize(*paths) - @root_node = Node.new - parse_paths(paths) - end - - # @param [string] path the path location to get the {ExpansionTree} subtree - # @return [ExpansionTree] the {ExpansionTree} at that location - def [](path) - unless @root_node.leaf? - er = ExpansionTree.create_from(@root_node[path] || Node.new) - er - else - ExpansionTree.new - end - end - - # - def expand?(path) - @root_node.has_key?(path) - end - - - # a node in the ExpansionTree - class Node < ActiveSupport::HashWithIndifferentAccess - # @return [boolean] true if this is a leaf node, false otherwise - def leaf? - none? - end - end - - private - - # given a set of SPaths, build a tree to describe - def parse_paths(paths=[]) - paths.each do |path| - working_tree = @root_node - path.split('.').each do |path_part| - working_tree[path_part] = Node.new unless working_tree[path_part] - working_tree = working_tree[path_part] - end - end - end - - def self.create_from(root_tree_node) - er = ExpansionTree.new() - er.root_node = root_tree_node - er - end - - end -end \ No newline at end of file + extend ActiveSupport::Concern + included do + @__expand = Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new + + # The SPaths for the expandable attributes you would like to expand. By default, no attributes are expanded. + # You can call this multiple times and new calls will override any previous calls + def set_json_expansion_paths(*expansions) + @__expand = Controllers::ApiNew::JbuilderExpansions.build_json_expansion_path_tree(*expansions) + end + + # Builds the {ExpansionTree}. This is rarely needed but could be helpful in certain specific cases + # @param [Array,Array] paths the paths to expand. If the first item is a {String} then this is an array of SPaths. If the first item is + # an {ExpansionTree}, this object returns that item + # @return [ExpansionTree] + def build_json_expansion_path_tree(*paths) + Controllers::ApiNew::JbuilderExpansions.build_json_expansion_path_tree(*paths) + end + + # Configures an attribute which can be expanded in an jbuilder template + # When shrunk, if you pass this is the equivalent of writing: + # `json.set! attribute, source&.to_houid` # This assumes you passed the :attribute as the attribute + # When expanded, this is the equivalent of: + # `json.set! attribute do + # json.partial! opts[:object] + # end` + # + # @param [Symbol] attribute the name of the attribute that you would like output. + # @param [any] source an object which with an attribute which can be expanded + # @option opts [JbuilderTemplate] :json the JBuilder object being used to generate the outputted JSON This is required. + # @option opts [ExpansionTree] :__expand the ExpansionTree for this current template. This is required. + # @option opts [Symbol] :as the method we call on 'object' when expanding the node. + def handle_expansion(attribute, source, opts = {}) + opts = opts.deep_symbolize_keys + opts[:__expand] ||= __expand + ExpansionTreeVisitor.handle_expansion(attribute, source, opts) + end + + # configures an attribute for an array which can be expanded in a jbuilder template + # + # When shrunk, this is the equivalent of writing: + # ```ruby + # json.set! attribute, source.map{|i| i&.to_houid} + # ```` + # When expanded, with the helper of this is the equivalent of writing: + # ```ruby + # json.(attribute) source do |item| # assumes opts[:as] is the same as "attribute" + # json.partial! item + # end + # @param [Symbol] attribute the name of the attribute that you would like output. + # @param [Enumerable] source an enumerable of objects, each of which has an attribute which can be expanded + # @option opts [JbuilderTemplate] :json the JBuilder object being used to generate the outputted JSON This is required. + # @option opts [ExpansionTree] :__expand the ExpansionTree for this current template. This is required. + # @option opts [Symbol] :as_item the method we call on each of the array items as part of a #handle_array_expansion call. + # @yieldparam [ItemExpansion] item if block is passed, an ItemExpansion will be yielded for each item for in the partial + def handle_array_expansion(attribute, source, opts = {}, &block) + opts = opts.deep_symbolize_keys + opts[:__expand] ||= __expand + ExpansionTreeVisitor.handle_array_expansion(attribute, source, opts, &block) + end + + helper_method :handle_expansion, :handle_array_expansion, :build_json_expansion_path_tree + end + + def self.build_json_expansion_path_tree(*paths) + request = ExpansionTree.new + paths = paths.flatten + if paths.count == 1 + if paths.first.is_a? String + request = ExpansionTree.new(*paths) + elsif paths.first.is_a? ExpansionTree + request = paths.first + end + elsif paths.any? + request = ExpansionTree.new(*paths) + end + + request + end + + # Applies Visitor(ish) pattern to an object. One of these is created for every new partial corresponding to a node in the tree + # + # Should not be used directly. + # + # @api private + class ExpansionTreeVisitor + # the attribute to add to the outputted JSON + # @return [Symbol] + attr_reader :attribute + + # the object we're visiting + attr_reader :object + + # @param [Symbol] attribute the attribute in the outputted JSON + # @param [Object,Enumerable] object the object being visited. object is an enumerable, then it's an array + # @option opts [JbuilderTemplate] :json the JBuilder object being used to generate the outputted JSON This is required. + # @option opts [ExpansionTree] :__expand the ExpansionTree for this current template. This is required. + # @option opts [Symbol] :as the method we call on 'object' when expanding the node. + # @option opts [Symbol] :item_as the method we call on each of the array items as part of a #handle_array_expansion call. + def initialize(attribute, object, opts) + @attribute = attribute + @object = object + @opts = opts.deep_symbolize_keys + end + + # the JBuilder object being used to generate the outputted JSON + # @return [JbuilderTemplate] the JBuilder object being used to generate the outputted JSON + def json + @opts[:json] + end + + # the ExpansionTree for the current partial + # @return [ExpansionTree] the tree for the current partial + def exp_request + @opts[:__expand] + end + + # the method we call on 'object' when expanding the node. Defaults to #attribute + # @return [Symbol] + def as + @opts[:as] || attribute + end + + # the method we call on each of the array items when expanding the node as part of a #handle_array_expansion call. Defaults to #attribute + # @return [Symbol] + def item_as + @opts[:item_as] || attribute + end + + def visit_expansion + if object.nil? + json.set! attribute, nil + elsif exp_request.expand? attribute + json.set! attribute do + json.partial! object, as: as, __expand: exp_request[attribute] + end + else + json.set! attribute, object&.to_houid + end + end + + # If #attribute is not set to expand then create an array of houids from the item in #object like: + # + # `json.friends ['friend_3254n132', 'friend_1245']` + # + # If #attribute is set to expand then create an array with the objects associated with the items. Alternatively, you + # can pass a block and this will yield an {ItemExpansion} so you can do your own manipulation of the specific item. + def visit_array_expansion + json.set! attribute do + if !exp_request.expand? attribute + json.array! object.map(&:to_houid) + else + object.each do |item| + json.child! do + if block_given? + yield(ItemExpansion.new(item, item_as, {json: json, __expand: exp_request[attribute]})) + else + ItemExpansion.new(item, item_as, {json: json, __expand: exp_request[attribute]}).handle_item_expansion + end + end + end + end + end + end + + def visit_item_expansion + json.partial! object, as: as, __expand: exp_request + end + + def self.handle_expansion(attribute, object, opts) + ExpansionTreeVisitor.new(attribute, object, opts).visit_expansion + end + + def self.handle_array_expansion(attribute, object, opts, &block) + ExpansionTreeVisitor.new(attribute, object, opts).visit_array_expansion(&block) + end + end + + class ItemExpansion + attr_reader :item, :as + + def initialize(item, as, opts = {}) + @item = item + @as = as + @json = opts[:json] + @__expand = opts[:__expand] + end + + def handle_item_expansion(object = nil) + if object.nil? + object = item + end + ExpansionTreeVisitor.new(nil, object, {as: as, json: @json, __expand: @__expand}).visit_item_expansion + end + end + + # an ExpansionTree takes a list of JSON SPath and then generates a tree for calculating what should be expanded + # To help understand why this a tree, consider the following SPaths: `supporter`, `nonprofit`, `nonprofit.user`. + # One could describe the SPath expansions as follows: + # + # ```ruby + # (root) + # | + # |---supporter + # | + # |---nonprofit + # | + # |--- user + # ``` + # + # @note You shouldn't be using the details of this class directly, you'll just be passing the object around + # as part of the various expansion requests + # @api private + class ExpansionTree + attr_accessor :root_node + + # @param [Array] paths the JSON SPaths for this tree + def initialize(*paths) + @root_node = Node.new + parse_paths(paths) + end + + # @param [string] path the path location to get the {ExpansionTree} subtree + # @return [ExpansionTree] the {ExpansionTree} at that location + def [](path) + if @root_node.leaf? + ExpansionTree.new + else + ExpansionTree.create_from(@root_node[path] || Node.new) + + end + end + + def expand?(path) + @root_node.has_key?(path) + end + + # a node in the ExpansionTree + class Node < ActiveSupport::HashWithIndifferentAccess + # @return [boolean] true if this is a leaf node, false otherwise + def leaf? + none? + end + end + + private + + # given a set of SPaths, build a tree to describe + def parse_paths(paths = []) + paths.each do |path| + working_tree = @root_node + path.split(".").each do |path_part| + working_tree[path_part] = Node.new unless working_tree[path_part] + working_tree = working_tree[path_part] + end + end + end + + def self.create_from(root_tree_node) + er = ExpansionTree.new + er.root_node = root_tree_node + er + end + end +end diff --git a/app/controllers/concerns/controllers/api_new/nonprofit/current.rb b/app/controllers/concerns/controllers/api_new/nonprofit/current.rb index 344f2ef65..15ed8439e 100644 --- a/app/controllers/concerns/controllers/api_new/nonprofit/current.rb +++ b/app/controllers/concerns/controllers/api_new/nonprofit/current.rb @@ -3,28 +3,25 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE - # You need this is in (ApiController)s. Eventually it should be used for all controllers but we're not there yet. module Controllers::ApiNew::Nonprofit::Current - extend ActiveSupport::Concern - included do - private + extend ActiveSupport::Concern + included do + private - def current_nonprofit - result = Nonprofit.find_by(houid:params[:nonprofit_id]) - if Rails.version < '5' && result.nil? - raise ActiveRecord::RecordNotFound.new - end + def current_nonprofit + result = Nonprofit.find_by(houid: params[:nonprofit_id]) + if Rails.version < "5" && result.nil? + raise ActiveRecord::RecordNotFound.new + end - result - end + result + end - def current_nonprofit_without_exception - begin - current_nonprofit - rescue - false - end - end - end + def current_nonprofit_without_exception + current_nonprofit + rescue + false + end + end end diff --git a/app/controllers/concerns/controllers/api_new/transaction/current.rb b/app/controllers/concerns/controllers/api_new/transaction/current.rb index b790755b4..481f406c1 100644 --- a/app/controllers/concerns/controllers/api_new/transaction/current.rb +++ b/app/controllers/concerns/controllers/api_new/transaction/current.rb @@ -3,18 +3,18 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Controllers::ApiNew::Transaction::Current - extend ActiveSupport::Concern - include Controllers::ApiNew::Nonprofit::Current + extend ActiveSupport::Concern + include Controllers::ApiNew::Nonprofit::Current - included do - private + included do + private - def current_transaction - result = @current_transaction - if result.nil? - result = current_nonprofit.transactions.find_by!(houid:params[:transaction_id] || params[:id]) - end - @current_transaction = result - end - end + def current_transaction + result = @current_transaction + if result.nil? + result = current_nonprofit.transactions.find_by!(houid: params[:transaction_id] || params[:id]) + end + @current_transaction = result + end + end end diff --git a/app/controllers/concerns/controllers/locale.rb b/app/controllers/concerns/controllers/locale.rb index 7a20defc8..f86da0275 100644 --- a/app/controllers/concerns/controllers/locale.rb +++ b/app/controllers/concerns/controllers/locale.rb @@ -4,33 +4,33 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE # rubocop:disable Style/ConditionalAssignment module Controllers::Locale - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do - around_action :switch_locale + included do + around_action :switch_locale - private + private - def switch_locale(&action) - locale =if available_locales.include?(params[:locale]) - params[:locale] - else - extract_locale_from_accept_language_header - end + def switch_locale(&action) + locale = if available_locales.include?(params[:locale]) + params[:locale] + else + extract_locale_from_accept_language_header + end - logger.debug "* Locale set to '#{locale}'" - I18n.with_locale(locale, &action) - end + logger.debug "* Locale set to '#{locale}'" + I18n.with_locale(locale, &action) + end - def extract_locale_from_accept_language_header - # override compared to Houdini because we don't have bess yet - Settings.language - end + def extract_locale_from_accept_language_header + # override compared to Houdini because we don't have bess yet + Settings.language + end - def available_locales - # we don't have bess so override - Settings.available_locales.map { |locale| locale.to_s } - end - end + def available_locales + # we don't have bess so override + Settings.available_locales.map { |locale| locale.to_s } + end + end end # rubocop:enable all diff --git a/app/controllers/concerns/controllers/nonprofit/authorization.rb b/app/controllers/concerns/controllers/nonprofit/authorization.rb index c65035b52..de9b3919c 100644 --- a/app/controllers/concerns/controllers/nonprofit/authorization.rb +++ b/app/controllers/concerns/controllers/nonprofit/authorization.rb @@ -3,36 +3,36 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Controllers::Nonprofit::Authorization - extend ActiveSupport::Concern - include Controllers::User::Authorization + extend ActiveSupport::Concern + include Controllers::User::Authorization - included do - helper_method :current_nonprofit_user? + included do + helper_method :current_nonprofit_user? - private + private - def authenticate_nonprofit_user! - reject_with_sign_in unless current_nonprofit_user? - end + def authenticate_nonprofit_user! + reject_with_sign_in unless current_nonprofit_user? + end - def authenticate_nonprofit_admin! - reject_with_sign_in unless current_nonprofit_admin? - end + def authenticate_nonprofit_admin! + reject_with_sign_in unless current_nonprofit_admin? + end - def current_nonprofit_user? - return false if params[:preview] - return false unless current_nonprofit_without_exception + def current_nonprofit_user? + return false if params[:preview] + return false unless current_nonprofit_without_exception - @current_nonprofit_user ||= current_role?( - %i[nonprofit_admin nonprofit_associate], - current_nonprofit_without_exception.id - ) || current_role?(:super_admin) - end + @current_nonprofit_user ||= current_role?( + %i[nonprofit_admin nonprofit_associate], + current_nonprofit_without_exception.id + ) || current_role?(:super_admin) + end - def current_nonprofit_admin? - return false if !current_user || current_user.roles.empty? + def current_nonprofit_admin? + return false if !current_user || current_user.roles.empty? - @current_nonprofit_admin ||= current_role?(:nonprofit_admin, current_nonprofit.id) || current_role?(:super_admin) - end - end + @current_nonprofit_admin ||= current_role?(:nonprofit_admin, current_nonprofit.id) || current_role?(:super_admin) + end + end end diff --git a/app/controllers/concerns/controllers/user/authorization.rb b/app/controllers/concerns/controllers/user/authorization.rb index 9267f7ecc..757bfd190 100644 --- a/app/controllers/concerns/controllers/user/authorization.rb +++ b/app/controllers/concerns/controllers/user/authorization.rb @@ -3,80 +3,80 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Controllers::User::Authorization - extend ActiveSupport::Concern - - # rubocop:disable Metrics/BlockLength - # rubocop:disable Layout/LineLength - included do - helper_method :current_role?, :administered_nonprofit - - protected - - def authenticate_user! - reject_with_sign_in unless current_user - end - - def reject_with_sign_in(msg = nil) - respond_to do |format| - format.json { raise AuthenticationError } - format.any { block_with_sign_in(msg) } - end - end - - def block_with_sign_in(msg = nil) - if current_user - redirect_to root_path(redirect_url: request.fullpath) - else - redirect_to new_user_session_path(redirect_url: request.fullpath), flash: { error: msg } - end - end - - def current_role?(role_names, host_id = nil) - return false unless current_user - - role_names = Array(role_names) - QueryRoles.user_has_role?(current_user.id, role_names, host_id) - end - - def authenticate_confirmed_user!(msg = nil) - if !current_user - reject_with_sign_in(msg) - elsif !current_user.confirmed? && !current_role?(%i[super_associate super_admin]) - respond_to do |format| - format.json { raise AuthenticationError } - format.any { redirect_to new_user_confirmation_path, flash: { error: 'You need to confirm your account to do that.' } } - end - end - end - - def authenticate_super_associate! - reject_with_sign_in 'Please login.' unless current_role?(:super_admin) || current_role?(:super_associate) - end - - def authenticate_super_admin! - reject_with_sign_in 'Please login.' unless current_role?(:super_admin) - end - - def store_location - referrer = request.fullpath - no_redirects = ['/users', '/signup', '/signin', '/users/sign_in', '/users/sign_up', '/users/password', - '/users/sign_out', /.*\.json.*/, %r{.*auth/facebook.*}] - - return if request.format.symbol == :json || no_redirects.map { |p| referrer.match(p) }.any? - - session[:previous_url] = referrer - end - - def administered_nonprofit - return nil unless current_user - - ::Nonprofit.where(id: QueryRoles.host_ids(current_user_id, %i[nonprofit_admin nonprofit_associate])).last - end - - def current_user_id - current_user&.id - end - end + extend ActiveSupport::Concern + + # rubocop:disable Metrics/BlockLength + # rubocop:disable Layout/LineLength + included do + helper_method :current_role?, :administered_nonprofit + + protected + + def authenticate_user! + reject_with_sign_in unless current_user + end + + def reject_with_sign_in(msg = nil) + respond_to do |format| + format.json { raise AuthenticationError } + format.any { block_with_sign_in(msg) } + end + end + + def block_with_sign_in(msg = nil) + if current_user + redirect_to root_path(redirect_url: request.fullpath) + else + redirect_to new_user_session_path(redirect_url: request.fullpath), flash: {error: msg} + end + end + + def current_role?(role_names, host_id = nil) + return false unless current_user + + role_names = Array(role_names) + QueryRoles.user_has_role?(current_user.id, role_names, host_id) + end + + def authenticate_confirmed_user!(msg = nil) + if !current_user + reject_with_sign_in(msg) + elsif !current_user.confirmed? && !current_role?(%i[super_associate super_admin]) + respond_to do |format| + format.json { raise AuthenticationError } + format.any { redirect_to new_user_confirmation_path, flash: {error: "You need to confirm your account to do that."} } + end + end + end + + def authenticate_super_associate! + reject_with_sign_in "Please login." unless current_role?(:super_admin) || current_role?(:super_associate) + end + + def authenticate_super_admin! + reject_with_sign_in "Please login." unless current_role?(:super_admin) + end + + def store_location + referrer = request.fullpath + no_redirects = ["/users", "/signup", "/signin", "/users/sign_in", "/users/sign_up", "/users/password", + "/users/sign_out", /.*\.json.*/, %r{.*auth/facebook.*}] + + return if request.format.symbol == :json || no_redirects.map { |p| referrer.match(p) }.any? + + session[:previous_url] = referrer + end + + def administered_nonprofit + return nil unless current_user + + ::Nonprofit.where(id: QueryRoles.host_ids(current_user_id, %i[nonprofit_admin nonprofit_associate])).last + end + + def current_user_id + current_user&.id + end + end end # rubocop:enable all diff --git a/app/controllers/concerns/controllers/x_frame.rb b/app/controllers/concerns/controllers/x_frame.rb index 3f29ac0d3..106ff70c5 100644 --- a/app/controllers/concerns/controllers/x_frame.rb +++ b/app/controllers/concerns/controllers/x_frame.rb @@ -3,19 +3,19 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE module Controllers::XFrame - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do - private + included do + private - # allows the page to be put in a frame, i.e. remove the X-Frame-Options header - def allow_framing - response.headers.delete('X-Frame-Options') if response.headers.has_key?('X-Frame-Options') - response.headers.delete('x-frame-options') if response.headers.has_key?('x-frame-options') - end + # allows the page to be put in a frame, i.e. remove the X-Frame-Options header + def allow_framing + response.headers.delete("X-Frame-Options") if response.headers.has_key?("X-Frame-Options") + response.headers.delete("x-frame-options") if response.headers.has_key?("x-frame-options") + end - def prevent_framing(value="SAMEORIGIN") - response.headers['X-Frame-Options'] = value - end - end -end \ No newline at end of file + def prevent_framing(value = "SAMEORIGIN") + response.headers["X-Frame-Options"] = value + end + end +end diff --git a/app/controllers/direct_debit_details_controller.rb b/app/controllers/direct_debit_details_controller.rb index ea9e00bbb..a9a5b1c3d 100644 --- a/app/controllers/direct_debit_details_controller.rb +++ b/app/controllers/direct_debit_details_controller.rb @@ -1,7 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class DirectDebitDetailsController < ApplicationController - - # POST /sepa # This endpoint is used for saving direct debit account details # when SEPA payment is selected in the donation widget. Actual charge is diff --git a/app/controllers/email_settings_controller.rb b/app/controllers/email_settings_controller.rb index 1c94c8b21..1b6f0d8ed 100644 --- a/app/controllers/email_settings_controller.rb +++ b/app/controllers/email_settings_controller.rb @@ -15,6 +15,4 @@ def create user = current_role?(:super_admin) ? User.find(params[:user_id]) : current_user render json: UpdateEmailSettings.save(params[:nonprofit_id], user.id, params[:email_settings]) end - end - diff --git a/app/controllers/emails_controller.rb b/app/controllers/emails_controller.rb index 60c2b324a..d01ff4baf 100644 --- a/app/controllers/emails_controller.rb +++ b/app/controllers/emails_controller.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EmailsController < ApplicationController - before_action :authenticate_user! - - def create - email = params[:email] - GenericMailer.delay.generic_mail(email[:from_email], email[:from_name], email[:message], email[:subject], email[:to_email], email[:to_name]) - render :json => {:notification => 'Email successfully sent'}, :status => :created - end + before_action :authenticate_user! + def create + email = params[:email] + GenericMailer.delay.generic_mail(email[:from_email], email[:from_name], email[:message], email[:subject], email[:to_email], email[:to_name]) + render json: {notification: "Email successfully sent"}, status: :created + end end diff --git a/app/controllers/event_discounts_controller.rb b/app/controllers/event_discounts_controller.rb index ae2996b5f..56684c556 100644 --- a/app/controllers/event_discounts_controller.rb +++ b/app/controllers/event_discounts_controller.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EventDiscountsController < ApplicationController include Controllers::EventHelper - before_action :authenticate_event_editor!, :except => [:index] + before_action :authenticate_event_editor!, except: [:index] rescue_from ActiveRecord::RecordInvalid, with: :record_invalid @@ -19,7 +19,7 @@ def index def update @event_discount = current_event.event_discounts.find(params[:id]) - + @event_discount.update!(event_discount_params) @event_discount end @@ -39,7 +39,6 @@ def event_discount_params end def record_invalid(error) - render status: :unprocessable_entity, json: {errors: error.record.errors } + render status: :unprocessable_entity, json: {errors: error.record.errors} end - end diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index e3954431f..37abc7fba 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -1,22 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EventsController < ApplicationController - include Controllers::EventHelper + include Controllers::EventHelper - helper_method :current_event_editor? + helper_method :current_event_editor? before_action :authenticate_nonprofit_user!, only: :name_and_id - before_action :authenticate_event_editor!, only: [:update, :soft_delete, :stats, :create, :duplicate] + before_action :authenticate_event_editor!, only: [:update, :soft_delete, :stats, :create, :duplicate] - - def index + def index @nonprofit = current_nonprofit - end + end def listings - render json: QueryEventMetrics.for_listings('nonprofit', current_nonprofit.id, params) + render json: QueryEventMetrics.for_listings("nonprofit", current_nonprofit.id, params) end - def show - @event = params[:event_slug] ? Event.find_by_slug!(params[:event_slug]) : Event.find_by_id!(params[:id]) + def show + @event = params[:event_slug] ? Event.find_by_slug!(params[:event_slug]) : Event.find(params[:id]) @event_background_image = FetchBackgroundImage.with_model(@event) @nonprofit = @event.nonprofit if @event.deleted && !current_event_editor? @@ -24,33 +23,33 @@ def show flash[:notice] = "Sorry, we couldn't find that event" return end - @organizer = QueryEventOrganizer.with_event(@event.id) - end + @organizer = QueryEventOrganizer.with_event(@event.id) + end - def create + def create render_json do - Time.use_zone(current_nonprofit.timezone || 'UTC') do + Time.use_zone(current_nonprofit.timezone || "UTC") do params[:event][:start_datetime] = Chronic.parse(params[:event][:start_datetime]) if params[:event][:start_datetime].present? params[:event][:end_datetime] = Chronic.parse(params[:event][:end_datetime]) if params[:event][:end_datetime].present? end - flash[:notice] = 'Your draft event has been created! Well done.' + flash[:notice] = "Your draft event has been created! Well done." ev = current_nonprofit.events.create(params[:event]) {url: "/events/#{ev.slug}", event: ev} end - end + end - def update - Time.use_zone(current_nonprofit.timezone || 'UTC') do + def update + Time.use_zone(current_nonprofit.timezone || "UTC") do params[:event][:start_datetime] = Chronic.parse(params[:event][:start_datetime]) if params[:event][:start_datetime].present? params[:event][:end_datetime] = Chronic.parse(params[:event][:end_datetime]) if params[:event][:end_datetime].present? end - current_event.update_attributes(params[:event]) - json_saved current_event, 'Successfully updated' - end + current_event.update_attributes(params[:event]) + json_saved current_event, "Successfully updated" + end # post 'nonprofits/:np_id/events/:event_id/duplicate' def duplicate - render_json { InsertDuplicate.event(current_event.id, current_user.profile.id)} + render_json { InsertDuplicate.event(current_event.id, current_user.profile.id) } end def activities @@ -58,24 +57,22 @@ def activities end def soft_delete - current_event.update_attribute(:deleted, params[:delete]) - render json: {} - end + current_event.update_attribute(:deleted, params[:delete]) + render json: {} + end - def metrics + def metrics render json: QueryEventMetrics.with_event_ids([current_event.id]).first - end + end - def stats - @event = current_event - @url = Format::Url.concat(root_url, @event.url) - @event_background_image = FetchBackgroundImage.with_model(@event) - render layout: 'layouts/embed' - end + def stats + @event = current_event + @url = Format::Url.concat(root_url, @event.url) + @event_background_image = FetchBackgroundImage.with_model(@event) + render layout: "layouts/embed" + end def name_and_id @events = current_nonprofit.events.not_deleted.order("events.name ASC") end - - end diff --git a/app/controllers/front_controller.rb b/app/controllers/front_controller.rb index 7bb24fec7..7c37a39f9 100755 --- a/app/controllers/front_controller.rb +++ b/app/controllers/front_controller.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class FrontController < ApplicationController def index - if !Nonprofit.any? - redirect_to onboard_path - elsif current_role?([:nonprofit_admin,:nonprofit_associate]) - redirect_to slugged_nonprofit_dashboard_path(administered_nonprofit) - elsif current_user - redirect_to '/profiles/' + current_user.profile.id.to_s - else - redirect_to new_user_session_path - end - end + if !Nonprofit.any? + redirect_to onboard_path + elsif current_role?([:nonprofit_admin, :nonprofit_associate]) + redirect_to slugged_nonprofit_dashboard_path(administered_nonprofit) + elsif current_user + redirect_to "/profiles/" + current_user.profile.id.to_s + else + redirect_to new_user_session_path + end + end end diff --git a/app/controllers/image_attachments_controller.rb b/app/controllers/image_attachments_controller.rb index 9f47cbbd6..ab48f4a90 100644 --- a/app/controllers/image_attachments_controller.rb +++ b/app/controllers/image_attachments_controller.rb @@ -1,24 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ImageAttachmentsController < ApplicationController - before_action :authenticate_confirmed_user! - def create - # must return json with a link attr - # http://editor.froala.com/server-integrations/php-image-upload - @image = ImageAttachment.new(:file => params[:file]) - if @image.save - render :json => {:link => @image.file_url} - else - render :json => @image.errors.full_messages, :status => :unprocessable_entity - end - end + before_action :authenticate_confirmed_user! + def create + # must return json with a link attr + # http://editor.froala.com/server-integrations/php-image-upload + @image = ImageAttachment.new(file: params[:file]) + if @image.save + render json: {link: @image.file_url} + else + render json: @image.errors.full_messages, status: :unprocessable_entity + end + end - def remove - @image = ImageAttachment.select{|img| img.file_url == params[:src]}.first - if @image - @image.destroy - render :json => @image - else - render :json => {}, :status => :unprocessable_entity - end - end + def remove + @image = ImageAttachment.select { |img| img.file_url == params[:src] }.first + if @image + @image.destroy + render json: @image + else + render json: {}, status: :unprocessable_entity + end + end end diff --git a/app/controllers/mailchimp_controller.rb b/app/controllers/mailchimp_controller.rb index 81d1159fb..2d174f394 100644 --- a/app/controllers/mailchimp_controller.rb +++ b/app/controllers/mailchimp_controller.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -# Rails 6 requires a matching controller for the `spec/views/mailchimp/nonprofit_user_subscribe.json.jbuilder_spec.rb` +# Rails 6 requires a matching controller for the `spec/views/mailchimp/nonprofit_user_subscribe.json.jbuilder_spec.rb` # and `spec/views/mailchimp/list.json.jbuilder_spec.rb` spec # This controller isn't currently used for anything else. class MailchimpController < ApplicationController -end \ No newline at end of file +end diff --git a/app/controllers/maps_controller.rb b/app/controllers/maps_controller.rb index 480f3b930..de89ead79 100644 --- a/app/controllers/maps_controller.rb +++ b/app/controllers/maps_controller.rb @@ -1,34 +1,32 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class MapsController < ApplicationController - include Controllers::NonprofitHelper + include Controllers::NonprofitHelper - before_action :authenticate_super_associate!, only: :all_supporters - before_action :authenticate_nonprofit_user!, only: [:all_npo_supporters, :specific_npo_supporters] + before_action :authenticate_super_associate!, only: :all_supporters + before_action :authenticate_nonprofit_user!, only: [:all_npo_supporters, :specific_npo_supporters] - # used on admin/nonprofits_map and front page - def all_npos - respond_to do |format| - format.html { redirect_to :root } - format.json { @map_data = Nonprofit.where("latitude IS NOT NULL").last(1000) } - end - end + # used on admin/nonprofits_map and front page + def all_npos + respond_to do |format| + format.html { redirect_to :root } + format.json { @map_data = Nonprofit.where.not(latitude: nil).last(1000) } + end + end - # used on admin/supporters_map - def all_supporters - @map_data = Supporter.where("latitude IS NOT NULL").last(1000) - end - - # used on npo dashboard - def all_npo_supporters - @map_data = Nonprofit.find(params['npo_id']).supporters.where("latitude IS NOT NULL").last(100) - end - - # used on supporter dashboard - def specific_npo_supporters - supporter_ids = params['supporter_ids']&.split(",")&.map { |s| s.to_i } || [] - supporters = Nonprofit.find(params['npo_id']).supporters.find(supporter_ids).last(500) - @map_data = supporters.map{|s| s if s.latitude != ''} - end + # used on admin/supporters_map + def all_supporters + @map_data = Supporter.where.not(latitude: nil).last(1000) + end + # used on npo dashboard + def all_npo_supporters + @map_data = Nonprofit.find(params["npo_id"]).supporters.where.not(latitude: nil).last(100) + end + # used on supporter dashboard + def specific_npo_supporters + supporter_ids = params["supporter_ids"]&.split(",")&.map { |s| s.to_i } || [] + supporters = Nonprofit.find(params["npo_id"]).supporters.find(supporter_ids).last(500) + @map_data = supporters.map { |s| s if s.latitude != "" } + end end diff --git a/app/controllers/nonprofits/activities_controller.rb b/app/controllers/nonprofits/activities_controller.rb index 87696c3aa..294cb383f 100644 --- a/app/controllers/nonprofits/activities_controller.rb +++ b/app/controllers/nonprofits/activities_controller.rb @@ -1,14 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class ActivitiesController < ApplicationController - include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + class ActivitiesController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_nonprofit_user! # get /nonprofits/:nonprofit_id/supporters/:supporter_id/activities def index render json: QueryActivities.for_timeline(params[:nonprofit_id], params[:supporter_id]) end - - end + end end - diff --git a/app/controllers/nonprofits/bank_accounts_controller.rb b/app/controllers/nonprofits/bank_accounts_controller.rb index 9073c33db..fbcbc6f43 100644 --- a/app/controllers/nonprofits/bank_accounts_controller.rb +++ b/app/controllers/nonprofits/bank_accounts_controller.rb @@ -1,64 +1,63 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class BankAccountsController < ApplicationController - include Controllers::NonprofitHelper - - before_action :authenticate_nonprofit_admin! - - # post /nonprofits/:nonprofit_id/bank_account - # must pass in the user's password as params[:password] - def create - if password_was_confirmed(params[:pw_token]) - render_json { InsertBankAccount.with_stripe(current_nonprofit, current_user, params[:bank_account]) } - else - render json: ["Please confirm your password"], status: :unprocessable_entity - end - end - - # get /nonprofits/:nonprofit_id/bank_account/confirmation - def confirmation - @nonprofit = Nonprofit.find(params[:nonprofit_id]) - @bank_account = @nonprofit.bank_account - end - - # post /nonprofits/:nonprofit_id/bank_account/confirmation - def confirm - npo = current_nonprofit - ba = npo.bank_account - if params[:token] == ba.confirmation_token - ba.update_attribute(:pending_verification, false) - flash[:notice] = "Your bank account is now confirmed!" - redirect_to nonprofits_payouts_path(npo) - else - redirect_to(nonprofits_donations_path(npo), {:flash => {:error => "We could not confirm this bank account. Please follow the exact link provided in the confirmation email."}}) - end - end - - # get /nonprofits/:nonprofit_id/bank_account/cancellation - def cancellation - @nonprofit = Nonprofit.find(params[:nonprofit_id]) - @bank_account = @nonprofit.bank_account - end - - # post /nonprofits/:nonprofit_id/bank_account/cancel - def cancel - npo = current_nonprofit - ba = npo.bank_account - if params[:token] == ba.confirmation_token - ba.destroy - flash[:notice] = "Your bank account has been removed." - redirect_to nonprofits_donations_path(npo) - else - redirect_to(nonprofits_donations_path(npo), {:flash => {:error => "We could not remove this bank account. Please follow the exact link provided in the email."}}) - end - end - - def resend_confirmation - npo = current_nonprofit - ba = npo.bank_account - NonprofitMailer.delay.new_bank_account_notification(ba) if ba.valid? - respond_to{|format| format.json{render json: {}}} - end - -end + class BankAccountsController < ApplicationController + include Controllers::NonprofitHelper + + before_action :authenticate_nonprofit_admin! + + # post /nonprofits/:nonprofit_id/bank_account + # must pass in the user's password as params[:password] + def create + if password_was_confirmed(params[:pw_token]) + render_json { InsertBankAccount.with_stripe(current_nonprofit, current_user, params[:bank_account]) } + else + render json: ["Please confirm your password"], status: :unprocessable_entity + end + end + + # get /nonprofits/:nonprofit_id/bank_account/confirmation + def confirmation + @nonprofit = Nonprofit.find(params[:nonprofit_id]) + @bank_account = @nonprofit.bank_account + end + + # post /nonprofits/:nonprofit_id/bank_account/confirmation + def confirm + npo = current_nonprofit + ba = npo.bank_account + if params[:token] == ba.confirmation_token + ba.update_attribute(:pending_verification, false) + flash[:notice] = "Your bank account is now confirmed!" + redirect_to nonprofits_payouts_path(npo) + else + redirect_to(nonprofits_donations_path(npo), {flash: {error: "We could not confirm this bank account. Please follow the exact link provided in the confirmation email."}}) + end + end + + # get /nonprofits/:nonprofit_id/bank_account/cancellation + def cancellation + @nonprofit = Nonprofit.find(params[:nonprofit_id]) + @bank_account = @nonprofit.bank_account + end + + # post /nonprofits/:nonprofit_id/bank_account/cancel + def cancel + npo = current_nonprofit + ba = npo.bank_account + if params[:token] == ba.confirmation_token + ba.destroy + flash[:notice] = "Your bank account has been removed." + redirect_to nonprofits_donations_path(npo) + else + redirect_to(nonprofits_donations_path(npo), {flash: {error: "We could not remove this bank account. Please follow the exact link provided in the email."}}) + end + end + + def resend_confirmation + npo = current_nonprofit + ba = npo.bank_account + NonprofitMailer.delay.new_bank_account_notification(ba) if ba.valid? + respond_to { |format| format.json { render json: {} } } + end + end end diff --git a/app/controllers/nonprofits/button_controller.rb b/app/controllers/nonprofits/button_controller.rb index 49107cfc3..a8199a61b 100644 --- a/app/controllers/nonprofits/button_controller.rb +++ b/app/controllers/nonprofits/button_controller.rb @@ -1,28 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class ButtonController < ApplicationController - include Controllers::NonprofitHelper + class ButtonController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_user! - before_action :authenticate_user! + def send_code + NonprofitMailer.delay.button_code(current_nonprofit, params[:to_email], params[:to_name], params[:from_email], params[:message], params[:code]) + render json: {}, status: 200 + end + def basic + @nonprofit = current_nonprofit + end - def send_code - NonprofitMailer.delay.button_code(current_nonprofit, params[:to_email], params[:to_name], params[:from_email], params[:message], params[:code]) - render json: {}, status: 200 - end + def guided + @nonprofit = current_nonprofit + end - def basic - @nonprofit = current_nonprofit - end - - def guided - @nonprofit = current_nonprofit - end - - def advanced - @nonprofit = current_nonprofit - end - -end + def advanced + @nonprofit = current_nonprofit + end + end end diff --git a/app/controllers/nonprofits/charges_controller.rb b/app/controllers/nonprofits/charges_controller.rb index 25ee872d2..bb95081e8 100644 --- a/app/controllers/nonprofits/charges_controller.rb +++ b/app/controllers/nonprofits/charges_controller.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class ChargesController < ApplicationController - include Controllers::NonprofitHelper + class ChargesController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user!, only: :index + before_action :authenticate_nonprofit_user!, only: :index - # get /nonprofit/:nonprofit_id/charges - def index - redirect_to controller: :payments, action: :index - end # def index - - end + # get /nonprofit/:nonprofit_id/charges + def index + redirect_to controller: :payments, action: :index + end # def index + end end diff --git a/app/controllers/nonprofits/custom_field_joins_controller.rb b/app/controllers/nonprofits/custom_field_joins_controller.rb index 87a67860c..1376abbab 100644 --- a/app/controllers/nonprofits/custom_field_joins_controller.rb +++ b/app/controllers/nonprofits/custom_field_joins_controller.rb @@ -1,41 +1,37 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class CustomFieldJoinsController < ApplicationController - - include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! - - def index - @custom_field_joins = current_nonprofit - .supporters.find(params[:supporter_id]) - .custom_field_joins.where("custom_field_master_id IN (SELECT id from custom_field_masters WHERE custom_field_masters.nonprofit_id = ?)", current_nonprofit.id) - .order('created_at DESC') - end - - # used for modify a single supporter's custom fields or a group of - # selected supporters' CFs or all supporters' CFs - def modify - if params[:custom_fields].blank? || params[:custom_fields].empty? - render json: {} - return - end - - if params[:selecting_all] - supporter_ids = QuerySupporters.full_filter_expr(current_nonprofit.id, params[:query]).select("supporters.id").execute.map{|h| h['id']} - else - supporter_ids = params[:supporter_ids]. map(&:to_i) - end - - render InsertCustomFieldJoins.in_bulk(current_nonprofit.id, supporter_ids, params[:custom_fields]) - end - - - def destroy - supporter = current_nonprofit.supporters.find(params[:supporter_id]) - supporter.custom_field_joins.find(params[:id]).destroy - render json: {}, status: :ok - end - - end + class CustomFieldJoinsController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_nonprofit_user! + + def index + @custom_field_joins = current_nonprofit + .supporters.find(params[:supporter_id]) + .custom_field_joins.where("custom_field_master_id IN (SELECT id from custom_field_masters WHERE custom_field_masters.nonprofit_id = ?)", current_nonprofit.id) + .order("created_at DESC") + end + + # used for modify a single supporter's custom fields or a group of + # selected supporters' CFs or all supporters' CFs + def modify + if params[:custom_fields].blank? || params[:custom_fields].empty? + render json: {} + return + end + + supporter_ids = if params[:selecting_all] + QuerySupporters.full_filter_expr(current_nonprofit.id, params[:query]).select("supporters.id").execute.map { |h| h["id"] } + else + params[:supporter_ids].map(&:to_i) + end + + render InsertCustomFieldJoins.in_bulk(current_nonprofit.id, supporter_ids, params[:custom_fields]) + end + + def destroy + supporter = current_nonprofit.supporters.find(params[:supporter_id]) + supporter.custom_field_joins.find(params[:id]).destroy + render json: {}, status: :ok + end + end end - diff --git a/app/controllers/nonprofits/custom_field_masters_controller.rb b/app/controllers/nonprofits/custom_field_masters_controller.rb index 17fad57b3..13bd8c71f 100644 --- a/app/controllers/nonprofits/custom_field_masters_controller.rb +++ b/app/controllers/nonprofits/custom_field_masters_controller.rb @@ -1,27 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class CustomFieldMastersController < ApplicationController - include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + class CustomFieldMastersController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_nonprofit_user! - def index - @custom_field_masters = current_nonprofit - .custom_field_masters - .order('id DESC') - .not_deleted - end + def index + @custom_field_masters = current_nonprofit + .custom_field_masters + .order("id DESC") + .not_deleted + end - def create - json_saved CreateCustomFieldMaster.create(current_nonprofit, params[:custom_field_master]) - end + def create + json_saved CreateCustomFieldMaster.create(current_nonprofit, params[:custom_field_master]) + end - def destroy - custom_field_master = current_nonprofit.custom_field_masters.find(params[:id]) - custom_field_master.update_attribute(:deleted, true) - custom_field_master.custom_field_joins.destroy_all - render json: {}, status: :ok - end - - end + def destroy + custom_field_master = current_nonprofit.custom_field_masters.find(params[:id]) + custom_field_master.update_attribute(:deleted, true) + custom_field_master.custom_field_joins.destroy_all + render json: {}, status: :ok + end + end end - diff --git a/app/controllers/nonprofits/donations_controller.rb b/app/controllers/nonprofits/donations_controller.rb index 7c8125228..c0426521d 100644 --- a/app/controllers/nonprofits/donations_controller.rb +++ b/app/controllers/nonprofits/donations_controller.rb @@ -1,87 +1,83 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class DonationsController < ApplicationController - include Controllers::NonprofitHelper + class DonationsController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user!, only: [:index, :update] - before_action :authenticate_campaign_editor!, only: [:create_offsite] - before_action :reject_for_deactivated_nonprofits, only: [:create] + before_action :authenticate_nonprofit_user!, only: [:index, :update] + before_action :authenticate_campaign_editor!, only: [:create_offsite] + before_action :reject_for_deactivated_nonprofits, only: [:create] - # get /nonprofit/:nonprofit_id/donations - def index - redirect_to controller: :payments, action: :index - end # def index + # get /nonprofit/:nonprofit_id/donations + def index + redirect_to controller: :payments, action: :index + end # def index - # post /nonprofits/:nonprofit_id/donations - def create + # post /nonprofits/:nonprofit_id/donations + def create + if params[:token] + params[:donation][:fee_covered] = params[:fee_covered] - if params[:token] - params[:donation][:fee_covered] = params[:fee_covered] - - params[:donation][:token] = params[:token] - return render_json{ InsertDonation.with_stripe(params[:donation], current_user) } - elsif params[:direct_debit_detail_id] - render JsonResp.new(params[:donation]){|data| - requires(:amount).as_int - requires(:supporter_id, :nonprofit_id) - # TODO - # requires_either(:card_id, :direct_debit_detail_id).as_int - optional(:dedication, :designation).as_string - optional(:campaign_id, :event_id).as_int - }.when_valid{|data| - - - InsertDonation.with_sepa(data) - - } - end - end + params[:donation][:token] = params[:token] + render_json { InsertDonation.with_stripe(params[:donation], current_user) } + elsif params[:direct_debit_detail_id] + render JsonResp.new(params[:donation]) { |data| + requires(:amount).as_int + requires(:supporter_id, :nonprofit_id) + # TODO + # requires_either(:card_id, :direct_debit_detail_id).as_int + optional(:dedication, :designation).as_string + optional(:campaign_id, :event_id).as_int + }.when_valid { |data| + InsertDonation.with_sepa(data) + } + end + end - # post /nonprofits/:nonprofit_id/donations/create_offsite - def create_offsite - render JsonResp.new(params[:donation]){|data| + # post /nonprofits/:nonprofit_id/donations/create_offsite + def create_offsite + render JsonResp.new(params[:donation]) { |data| requires(:amount).as_int.min(1) requires(:supporter_id, :nonprofit_id).as_int optional(:dedication, :designation).as_string optional(:campaign_id, :event_id).as_int optional(:date).as_date - optional(:offsite_payment).nested{ - optional(:kind).one_of('cash', 'check') + optional(:offsite_payment).nested { + optional(:kind).one_of("cash", "check") optional(:check_number) } - }.when_valid{|data| InsertDonation.offsite(data)} - end + }.when_valid { |data| InsertDonation.offsite(data) } + end - def update - render_json{ UpdateDonation.update_payment(params[:id], params[:donation]) } - end + def update + render_json { UpdateDonation.update_payment(params[:id], params[:donation]) } + end - # put /nonprofits/:nonprofit_id/donations/:id - # update designation, dedication, or comment on a donation in the followup - def followup - nonprofit = Nonprofit.find(params[:nonprofit_id]) - donation = nonprofit.donations.find(params[:id]) - json_saved UpdateDonation.from_followup(donation, params[:donation]) - end + # put /nonprofits/:nonprofit_id/donations/:id + # update designation, dedication, or comment on a donation in the followup + def followup + nonprofit = Nonprofit.find(params[:nonprofit_id]) + donation = nonprofit.donations.find(params[:id]) + json_saved UpdateDonation.from_followup(donation, params[:donation]) + end - # this is a special, weird case - private + # this is a special, weird case + private - def current_campaign - if !@campaign && params[:donation] && params[:donation][:campaign_id] - @campaign = Campaign.where('id = ? ', params[:donation][:campaign_id]).first - end - return @campaign - end + def current_campaign + if !@campaign && params[:donation] && params[:donation][:campaign_id] + @campaign = Campaign.where("id = ? ", params[:donation][:campaign_id]).first + end + @campaign + end - def current_campaign_editor? - !params[:preview] && (current_nonprofit_user? || (current_campaign && current_role?(:campaign_editor, current_campaign.id)) || current_role?(:super_admin)) - end + def current_campaign_editor? + !params[:preview] && (current_nonprofit_user? || (current_campaign && current_role?(:campaign_editor, current_campaign.id)) || current_role?(:super_admin)) + end - def authenticate_campaign_editor! - unless current_campaign_editor? - block_with_sign_in 'You need to be a campaign editor to do that.' - end - end - end + def authenticate_campaign_editor! + unless current_campaign_editor? + block_with_sign_in "You need to be a campaign editor to do that." + end + end + end end diff --git a/app/controllers/nonprofits/email_lists_controller.rb b/app/controllers/nonprofits/email_lists_controller.rb index 25a0d8fbc..e479ba15c 100644 --- a/app/controllers/nonprofits/email_lists_controller.rb +++ b/app/controllers/nonprofits/email_lists_controller.rb @@ -1,17 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class EmailListsController < ApplicationController - include Controllers::NonprofitHelper + class EmailListsController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + before_action :authenticate_nonprofit_user! - def index - render_json{ Qx.fetch(:email_lists, nonprofit_id: params[:nonprofit_id]) } - end + def index + render_json { Qx.fetch(:email_lists, nonprofit_id: params[:nonprofit_id]) } + end - def create - tag_master_ids = params['tag_masters'].values.map(&:to_i) - render_json{ InsertEmailLists.for_mailchimp(params[:nonprofit_id], tag_master_ids) } + def create + tag_master_ids = params["tag_masters"].values.map(&:to_i) + render_json { InsertEmailLists.for_mailchimp(params[:nonprofit_id], tag_master_ids) } + end end end -end diff --git a/app/controllers/nonprofits/imports_controller.rb b/app/controllers/nonprofits/imports_controller.rb index 9498680a8..8638faa7b 100644 --- a/app/controllers/nonprofits/imports_controller.rb +++ b/app/controllers/nonprofits/imports_controller.rb @@ -6,7 +6,7 @@ class ImportsController < ApplicationController before_action :authenticate_nonprofit_user! # post /nonprofits/:nonprofit_id/imports def create - render_json{ + render_json { InsertImport.delay.from_csv_safe({ nonprofit_id: params[:nonprofit_id], user_id: current_user.id, diff --git a/app/controllers/nonprofits/miscellaneous_np_infos_controller.rb b/app/controllers/nonprofits/miscellaneous_np_infos_controller.rb index 639c4bc03..c87903247 100644 --- a/app/controllers/nonprofits/miscellaneous_np_infos_controller.rb +++ b/app/controllers/nonprofits/miscellaneous_np_infos_controller.rb @@ -12,7 +12,6 @@ def show render_json { FetchMiscellaneousNpInfo.fetch(params[:nonprofit_id]) } end end - end def update @@ -20,7 +19,7 @@ def update format.json { render_json { update = UpdateMiscellaneousNpInfo.update(params[:nonprofit_id], params[:miscellaneous_np_info]) - #flash[:notice] = "Your Miscellaneous Settings have been saved" + # flash[:notice] = "Your Miscellaneous Settings have been saved" update } } diff --git a/app/controllers/nonprofits/nonprofit_keys_controller.rb b/app/controllers/nonprofits/nonprofit_keys_controller.rb index fb1f6ce33..b903a45bb 100644 --- a/app/controllers/nonprofits/nonprofit_keys_controller.rb +++ b/app/controllers/nonprofits/nonprofit_keys_controller.rb @@ -1,39 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class NonprofitKeysController < ApplicationController - include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + class NonprofitKeysController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_nonprofit_user! - # get /nonprofits/:nonprofit_id/nonprofit_keys - # pass in the :select query param, which is the name of the column of the specific token you want - def index - render_json{QueryNonprofitKeys.get_key(current_nonprofit.id, params[:select])} - end + # get /nonprofits/:nonprofit_id/nonprofit_keys + # pass in the :select query param, which is the name of the column of the specific token you want + def index + render_json { QueryNonprofitKeys.get_key(current_nonprofit.id, params[:select]) } + end - # Redirects to the mailchimp OAuth2 landing page, first setting the nonprofit id in the session - # GET /nonprofits/:nonprofit_id/nonprofit_keys/mailchimp_login - def mailchimp_login - session[:current_mailchimp_nonprofit_id] = current_nonprofit.id - redirect_to "https://login.mailchimp.com/oauth2/authorize?response_type=code&client_id=#{ENV['MAILCHIMP_OAUTH_CLIENT_ID']}", - allow_other_host: true - end + # Redirects to the mailchimp OAuth2 landing page, first setting the nonprofit id in the session + # GET /nonprofits/:nonprofit_id/nonprofit_keys/mailchimp_login + def mailchimp_login + session[:current_mailchimp_nonprofit_id] = current_nonprofit.id + redirect_to "https://login.mailchimp.com/oauth2/authorize?response_type=code&client_id=#{ENV["MAILCHIMP_OAUTH_CLIENT_ID"]}", + allow_other_host: true + end - # After the user OAuths mailchimp, they are redirected to /mailchimp-landing - # This action then redirects them back to /settings - # GET /mailchimp-landing - def mailchimp_landing - @nonprofit = Nonprofit.find(session[:current_mailchimp_nonprofit_id]) - session.delete(:current_mailchimp_nonprofit_id) - begin - session[:mailchimp_access_token] = InsertNonprofitKeys.insert_mailchimp_access_token(@nonprofit.id, params[:code]) - rescue Exception => e - flash[:notice] = "Unable to connect to your Mailchimp account, please try again. (Error: #{e})" - redirect_to '/settings' - return + # After the user OAuths mailchimp, they are redirected to /mailchimp-landing + # This action then redirects them back to /settings + # GET /mailchimp-landing + def mailchimp_landing + @nonprofit = Nonprofit.find(session[:current_mailchimp_nonprofit_id]) + session.delete(:current_mailchimp_nonprofit_id) + begin + session[:mailchimp_access_token] = InsertNonprofitKeys.insert_mailchimp_access_token(@nonprofit.id, params[:code]) + rescue Exception => e + flash[:notice] = "Unable to connect to your Mailchimp account, please try again. (Error: #{e})" + redirect_to "/settings" + return + end + redirect_to nonprofits_supporters_path @nonprofit, "show-modal" => "mailchimpSettingsModal" end - redirect_to nonprofits_supporters_path @nonprofit, 'show-modal' => 'mailchimpSettingsModal' end - -end end diff --git a/app/controllers/nonprofits/payments_controller.rb b/app/controllers/nonprofits/payments_controller.rb index 430093b05..aeb850b53 100644 --- a/app/controllers/nonprofits/payments_controller.rb +++ b/app/controllers/nonprofits/payments_controller.rb @@ -1,31 +1,30 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class PaymentsController < ApplicationController - include Controllers::NonprofitHelper + class PaymentsController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + before_action :authenticate_nonprofit_user! - - # get /nonprofit/:nonprofit_id/payments - def index - @nonprofit = current_nonprofit - respond_to do |format| - format.html do + # get /nonprofit/:nonprofit_id/payments + def index + @nonprofit = current_nonprofit + respond_to do |format| + format.html do @panels_layout = true end - format.json do - @response = QueryPayments.full_search(params[:nonprofit_id], params) + format.json do + @response = QueryPayments.full_search(params[:nonprofit_id], params) render json: @response, status: :ok - end - end - end # def index + end + end + end # def index def export begin @nonprofit = current_nonprofit @user = current_user_id - ExportPayments::initiate_export(@nonprofit.id, params, @user) + ExportPayments.initiate_export(@nonprofit.id, params, @user) rescue => e e end @@ -37,10 +36,10 @@ def export end end - def show - @nonprofit = current_nonprofit - @payment = @nonprofit.payments.find(params[:id]) - end # def show + def show + @nonprofit = current_nonprofit + @payment = @nonprofit.payments.find(params[:id]) + end # def show def update @payment = current_nonprofit.payments.find(params[:id]) @@ -52,7 +51,7 @@ def destroy @payment = current_nonprofit.payments.find(params[:id]) if @payment.offsite_payment.nil? render json: {}, status: :unprocessable_entity - return # You may only destroy offline payments + nil # You may only destroy offline payments else @payment.donation.destroy if @payment.donation.present? @payment.tickets.destroy_all if @payment.tickets.present? @@ -66,27 +65,28 @@ def destroy # post /nonprofits/:nonprofit_id/payments/:id/resend_donor_receipt def resend_donor_receipt payment = Payment.find(params[:id]) - if payment.kind == 'Donation' || payment.kind == 'RecurringDonation' + if payment.kind == "Donation" || payment.kind == "RecurringDonation" JobQueue.queue(JobTypes::DonorPaymentNotificationJob, payment.donation.id, payment.id) - elsif payment.kind == 'Ticket' + elsif payment.kind == "Ticket" TicketMailer.followup(payment.tickets.pluck(:id), payment.charge.id).deliver - elsif payment.kind == 'Refund' + elsif payment.kind == "Refund" Delayed::Job.enqueue JobTypes::DonorRefundNotificationJob.new(payment.refund.id) end render json: {} end + # post /nonprofits/:nonprofit_id/payments/:id/resend_admin_receipt # pass user_id of the admin to send to def resend_admin_receipt payment = Payment.find(params[:id]) - if payment.kind == 'Donation' || payment.kind == 'RecurringDonation' + if payment.kind == "Donation" || payment.kind == "RecurringDonation" JobQueue.queue(JobTypes::NonprofitPaymentNotificationJob, payment.donation.id, payment.id, current_user.id) - elsif payment.kind == 'Ticket' + elsif payment.kind == "Ticket" JobQueue.queue(JobTypes::TicketMailerReceiptAdminJob, payment.tickets.pluck(:id), current_user.id) - elsif payment.kind == 'Refund' + elsif payment.kind == "Refund" Delayed::Job.enqueue JobTypes::NonprofitRefundNotificationJob.new(payment.refund.id, current_user.id) end render json: {} end - end # class PaymentsController + end # class PaymentsController end # module Nonprofits diff --git a/app/controllers/nonprofits/payouts_controller.rb b/app/controllers/nonprofits/payouts_controller.rb index 97dae43cf..f7b8b5570 100644 --- a/app/controllers/nonprofits/payouts_controller.rb +++ b/app/controllers/nonprofits/payouts_controller.rb @@ -1,55 +1,54 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class PayoutsController < ApplicationController - include Controllers::NonprofitHelper - - before_action :authenticate_nonprofit_admin!, only: :create - before_action :authenticate_nonprofit_user!, only: [:index, :show] - - def create - payout = InsertPayout.with_stripe(current_nonprofit.id, { - stripe_account_id: current_nonprofit.stripe_account_id, - email: current_user.email, - user_ip: current_user.current_sign_in_ip, - bank_name: current_nonprofit.bank_account.name - }, {before_date: params[:before_date]}) - - if payout['failure_message'].present? - flash[:notice] = "The payout failed: #{payout['failure_message']}" - render json: payout, status: :unprocessable_entity - else - flash[:notice] = 'We successfully submitted your payout! View status and receipts below.' - render json: payout, status: :ok - end - end + class PayoutsController < ApplicationController + include Controllers::NonprofitHelper + + before_action :authenticate_nonprofit_admin!, only: :create + before_action :authenticate_nonprofit_user!, only: [:index, :show] + + def create + payout = InsertPayout.with_stripe(current_nonprofit.id, { + stripe_account_id: current_nonprofit.stripe_account_id, + email: current_user.email, + user_ip: current_user.current_sign_in_ip, + bank_name: current_nonprofit.bank_account.name + }, {before_date: params[:before_date]}) + + if payout["failure_message"].present? + flash[:notice] = "The payout failed: #{payout["failure_message"]}" + render json: payout, status: :unprocessable_entity + else + flash[:notice] = "We successfully submitted your payout! View status and receipts below." + render json: payout, status: :ok + end + end - def index - @nonprofit = Nonprofit.find(params[:nonprofit_id]) - @payouts = @nonprofit.payouts.order('created_at DESC') - balances = QueryPayments.nonprofit_balances(params[:nonprofit_id]) - @available_gross = balances['available']['gross'] - @available_net = balances['available']['net'] - @pending_net = balances['pending']['net'] - @can_make_payouts = @nonprofit.can_make_payouts? - @verification_status = @nonprofit&.stripe_account&.verification_status || :unverified + def index + @nonprofit = Nonprofit.find(params[:nonprofit_id]) + @payouts = @nonprofit.payouts.order("created_at DESC") + balances = QueryPayments.nonprofit_balances(params[:nonprofit_id]) + @available_gross = balances["available"]["gross"] + @available_net = balances["available"]["net"] + @pending_net = balances["pending"]["net"] + @can_make_payouts = @nonprofit.can_make_payouts? + @verification_status = @nonprofit&.stripe_account&.verification_status || :unverified - @deadline = @nonprofit&.stripe_account&.deadline && @nonprofit.stripe_account.deadline.in_time_zone(@nonprofit.timezone).strftime('%B %e, %Y at %l:%M:%S %p') + @deadline = @nonprofit&.stripe_account&.deadline && @nonprofit.stripe_account.deadline.in_time_zone(@nonprofit.timezone).strftime("%B %e, %Y at %l:%M:%S %p") - @steps_to_payout = @nonprofit.steps_to_payout - end + @steps_to_payout = @nonprofit.steps_to_payout + end - # get /nonprofits/:nonprofit_id/payouts/:id - def show - payout = current_nonprofit.payouts.find(params[:id]) - respond_to do |format| - format.json{render json: payout} - format.csv do - payments = QueryPayments.for_payout(params[:nonprofit_id], params[:id]) - filename = "payout-#{payout.created_at.strftime("%m-%d-%Y")}" - send_data(Format::Csv.from_vectors(payments), filename: "#{filename}.csv") + # get /nonprofits/:nonprofit_id/payouts/:id + def show + payout = current_nonprofit.payouts.find(params[:id]) + respond_to do |format| + format.json { render json: payout } + format.csv do + payments = QueryPayments.for_payout(params[:nonprofit_id], params[:id]) + filename = "payout-#{payout.created_at.strftime("%m-%d-%Y")}" + send_data(Format::Csv.from_vectors(payments), filename: "#{filename}.csv") + end end end end - -end end diff --git a/app/controllers/nonprofits/recurring_donations_controller.rb b/app/controllers/nonprofits/recurring_donations_controller.rb index 8f83892dc..18dd27121 100644 --- a/app/controllers/nonprofits/recurring_donations_controller.rb +++ b/app/controllers/nonprofits/recurring_donations_controller.rb @@ -1,95 +1,94 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class RecurringDonationsController < ApplicationController - include Controllers::NonprofitHelper + class RecurringDonationsController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user!, except: [:create] - before_action :reject_for_deactivated_nonprofits, only: [:create] + before_action :authenticate_nonprofit_user!, except: [:create] + before_action :reject_for_deactivated_nonprofits, only: [:create] - # get /nonprofits/:nonprofit_id/recurring_donations - def index - @nonprofit = current_nonprofit - @panels_layout = true - respond_to do |format| - format.html - format.json do - # set dashboard params include externally active and failed - #TODO move into javascript - params[:active] = true + # get /nonprofits/:nonprofit_id/recurring_donations + def index + @nonprofit = current_nonprofit + @panels_layout = true + respond_to do |format| + format.html + format.json do + # set dashboard params include externally active and failed + # TODO move into javascript + params[:active] = true - render json: QueryRecurringDonations.full_list(params[:nonprofit_id], params.merge(end_date_gt_or_equal: Time.current)) + render json: QueryRecurringDonations.full_list(params[:nonprofit_id], params.merge(end_date_gt_or_equal: Time.current)) + end end - end - end - - def export - begin - @nonprofit = current_nonprofit - @user = current_user_id - #TODO move into javascript - if params.key?(:active_and_not_failed) - params.delete(:active) if params.key?(:active) - params.delete(:failed) if params.key?(:failed) - end + end - [:active_and_not_failed, :active, :failed, :fulfilled].each do |k| - if params.key?(k) - params[k] = params[k] == "true" - end - end + def export + begin + @nonprofit = current_nonprofit + @user = current_user_id + # TODO move into javascript + if params.key?(:active_and_not_failed) + params.delete(:active) if params.key?(:active) + params.delete(:failed) if params.key?(:failed) + end - params[:root_url] = root_url + [:active_and_not_failed, :active, :failed, :fulfilled].each do |k| + if params.key?(k) + params[k] = params[k] == "true" + end + end - ExportRecurringDonations::initiate_export(@nonprofit.id, params, [current_user.id]) - rescue => e - e - end - if e.nil? - flash[:notice] = "Your export was successfully initiated and you'll be emailed at #{current_user.email} as soon as it's available. Feel free to use the site in the meantime." - render json: {}, status: :ok - else - render json: e, status: :ok - end - end + params[:root_url] = root_url - def show - @recurring_donation = current_recurring_donation - respond_to {|format| format.json} - end + ExportRecurringDonations.initiate_export(@nonprofit.id, params, [current_user.id]) + rescue => e + e + end + if e.nil? + flash[:notice] = "Your export was successfully initiated and you'll be emailed at #{current_user.email} as soon as it's available. Feel free to use the site in the meantime." + render json: {}, status: :ok + else + render json: e, status: :ok + end + end - def destroy - UpdateRecurringDonations.cancel(params[:id], current_user.email) - json_saved current_recurring_donation - end + def show + @recurring_donation = current_recurring_donation + respond_to { |format| format.json } + end - def update - json_saved UpdateRecurringDonations - .update(current_recurring_donation, params[:recurring_donation]) - end + def destroy + UpdateRecurringDonations.cancel(params[:id], current_user.email) + json_saved current_recurring_donation + end - # post /nonprofits/:nonprofit_id/recurring_donations - def create - if params[:recurring_donation][:token] - render_json{ InsertRecurringDonation.with_stripe(params[:recurring_donation]) } - elsif params[:recurring_donation][:direct_debit_detail_id] - render JsonResp.new(params[:recurring_donation]){|data| - requires(:amount).as_int - requires(:supporter_id, :nonprofit_id, :direct_debit_detail_id).as_int - optional(:dedication, :designation).as_string - optional(:campaign_id, :event_id).as_int - }.when_valid{|data| - InsertRecurringDonation.with_sepa(data) - } - else - render json: {}, status: 422 + def update + json_saved UpdateRecurringDonations + .update(current_recurring_donation, params[:recurring_donation]) end - end -private + # post /nonprofits/:nonprofit_id/recurring_donations + def create + if params[:recurring_donation][:token] + render_json { InsertRecurringDonation.with_stripe(params[:recurring_donation]) } + elsif params[:recurring_donation][:direct_debit_detail_id] + render JsonResp.new(params[:recurring_donation]) { |data| + requires(:amount).as_int + requires(:supporter_id, :nonprofit_id, :direct_debit_detail_id).as_int + optional(:dedication, :designation).as_string + optional(:campaign_id, :event_id).as_int + }.when_valid { |data| + InsertRecurringDonation.with_sepa(data) + } + else + render json: {}, status: 422 + end + end - def current_recurring_donation - @recurring_donation ||= current_nonprofit.recurring_donations.find params[:id] - end + private -end + def current_recurring_donation + @recurring_donation ||= current_nonprofit.recurring_donations.find params[:id] + end + end end diff --git a/app/controllers/nonprofits/refunds_controller.rb b/app/controllers/nonprofits/refunds_controller.rb index 870833500..e21c12726 100644 --- a/app/controllers/nonprofits/refunds_controller.rb +++ b/app/controllers/nonprofits/refunds_controller.rb @@ -1,21 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class RefundsController < ApplicationController - include Controllers::NonprofitHelper + class RefundsController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + before_action :authenticate_nonprofit_user! - # post /charges/:charge_id/refunds - def create + # post /charges/:charge_id/refunds + def create charge = current_nonprofit.charges.find(params[:charge_id]) - params[:refund][:user_id] = current_user.id - render_json{ InsertRefunds.with_stripe(charge, params['refund']) } - end + params[:refund][:user_id] = current_user.id + render_json { InsertRefunds.with_stripe(charge, params["refund"]) } + end - def index - charge = current_nonprofit.charges.find(params[:charge_id]) - @refunds = charge.refunds - end - end + def index + charge = current_nonprofit.charges.find(params[:charge_id]) + @refunds = charge.refunds + end + end end - diff --git a/app/controllers/nonprofits/reports_controller.rb b/app/controllers/nonprofits/reports_controller.rb index 9dd6ca5cc..a159a5b31 100644 --- a/app/controllers/nonprofits/reports_controller.rb +++ b/app/controllers/nonprofits/reports_controller.rb @@ -8,7 +8,7 @@ def end_of_year respond_to do |format| format.csv do filename = "end-of-year-report-#{params[:year]}.csv" - data = QuerySupporters.year_aggregate_report(params[:nonprofit_id], {:year => params[:year]}) + data = QuerySupporters.year_aggregate_report(params[:nonprofit_id], {year: params[:year]}) send_data(Format::Csv.from_array(data), filename: filename) end end @@ -18,17 +18,17 @@ def end_of_year_custom respond_to do |format| format.csv do name_description = nil - if (params[:year]) + if params[:year] name_description = params[:year] - elsif (params[:start]) + elsif params[:start] name_description = "from-#{params[:start]}" - if (params[:end]) + if params[:end] name_description += "-to-#{params[:end]}" end end filename = "aggregate-report-#{name_description}.csv" - data = QuerySupporters.year_aggregate_report(params[:nonprofit_id], {:year => params[:year], :start => params[:start], :end => params[:end]}) + data = QuerySupporters.year_aggregate_report(params[:nonprofit_id], {year: params[:year], start: params[:start], end: params[:end]}) send_data(Format::Csv.from_array(data), filename: filename) end end diff --git a/app/controllers/nonprofits/stripe_accounts_controller.rb b/app/controllers/nonprofits/stripe_accounts_controller.rb index 0c7805971..56a0f63e6 100644 --- a/app/controllers/nonprofits/stripe_accounts_controller.rb +++ b/app/controllers/nonprofits/stripe_accounts_controller.rb @@ -1,73 +1,70 @@ module Nonprofits - class StripeAccountsController < ApplicationController - include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_admin! + class StripeAccountsController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_nonprofit_admin! - layout 'layouts/apified' + layout "layouts/apified" - def index - render_json do + def index + render_json do + raise ActiveRecord::RecordNotFound unless current_nonprofit.stripe_account - raise ActiveRecord::RecordNotFound unless current_nonprofit.stripe_account - - current_nonprofit.stripe_account.to_json( except: [:object, :id, :created_at, :updated_at], methods: [:verification_status, :deadline]) - end - end + current_nonprofit.stripe_account.to_json(except: [:object, :id, :created_at, :updated_at], methods: [:verification_status, :deadline]) + end + end - # this is the start page when someone needs to verify their nonprofit - def verification - @theme = 'minimal' - @current_nonprofit = current_nonprofit - end + # this is the start page when someone needs to verify their nonprofit + def verification + @theme = "minimal" + @current_nonprofit = current_nonprofit + end - # html page where we check repeatedly whether we received a verification update - def confirm - @theme = 'minimal' - @current_nonprofit = current_nonprofit - end + # html page where we check repeatedly whether we received a verification update + def confirm + @theme = "minimal" + @current_nonprofit = current_nonprofit + end - def begin_verification - stripe_account_for_nonprofit = StripeAccountUtils.find_or_create(current_nonprofit.id) - current_nonprofit.reload + def begin_verification + StripeAccountUtils.find_or_create(current_nonprofit.id) + current_nonprofit.reload - status = NonprofitVerificationProcessStatus.where('stripe_account_id = ?', current_nonprofit.stripe_account_id).first - unless status - status = NonprofitVerificationProcessStatus.new(stripe_account_id: current_nonprofit.stripe_account_id) - end + status = NonprofitVerificationProcessStatus.where("stripe_account_id = ?", current_nonprofit.stripe_account_id).first + status ||= NonprofitVerificationProcessStatus.new(stripe_account_id: current_nonprofit.stripe_account_id) - unless status.started_at - status.started_at = DateTime.now - end + unless status.started_at + status.started_at = DateTime.now + end - status.save! + status.save! - render json:{}, status: :ok - end + render json: {}, status: :ok + end - # html page when a link failed - def retry - @theme = 'minimal' - @current_nonprofit = current_nonprofit - end + # html page when a link failed + def retry + @theme = "minimal" + @current_nonprofit = current_nonprofit + end - def account_link - stripe_account_for_nonprofit = StripeAccountUtils.find_or_create(current_nonprofit.id) - current_nonprofit.reload + def account_link + StripeAccountUtils.find_or_create(current_nonprofit.id) + current_nonprofit.reload - if (current_nonprofit.stripe_account_id) - render json: Stripe::AccountLink.create({ - account:current_nonprofit.stripe_account_id, - refresh_url: nonprofits_stripe_account_url(current_nonprofit.id, {return_location: params[:return_location]}), - return_url: confirm_nonprofits_stripe_account_url(current_nonprofit.id, {return_location: params[:return_location]}), - type: 'account_onboarding', - collection_options: { - fields: 'eventually_due', - future_requirements: 'include', - } - }).to_json, status: 200 - else - render json:{error: "No Stripe account could be found or created. Please contact support@commitchange.com for assistance."}, status: 400 - end - end + if current_nonprofit.stripe_account_id + render json: Stripe::AccountLink.create({ + account: current_nonprofit.stripe_account_id, + refresh_url: nonprofits_stripe_account_url(current_nonprofit.id, {return_location: params[:return_location]}), + return_url: confirm_nonprofits_stripe_account_url(current_nonprofit.id, {return_location: params[:return_location]}), + type: "account_onboarding", + collection_options: { + fields: "eventually_due", + future_requirements: "include" + } + }).to_json, status: 200 + else + render json: {error: "No Stripe account could be found or created. Please contact support@commitchange.com for assistance."}, status: 400 + end end + end end diff --git a/app/controllers/nonprofits/supporter_notes_controller.rb b/app/controllers/nonprofits/supporter_notes_controller.rb index e6bc28b6e..4703aa5b8 100644 --- a/app/controllers/nonprofits/supporter_notes_controller.rb +++ b/app/controllers/nonprofits/supporter_notes_controller.rb @@ -1,31 +1,31 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class SupporterNotesController < ApplicationController - include Controllers::NonprofitHelper + class SupporterNotesController < ApplicationController + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user!, except: [:create] + before_action :authenticate_nonprofit_user!, except: [:create] - # post /nonprofits/:nonprofit_id/supporters/:supporter_id/supporter_notes - def create - render json: [Supporter.find(params[:supporter_id]).supporter_notes.create!(create_params.merge(user: current_user))] - end + # post /nonprofits/:nonprofit_id/supporters/:supporter_id/supporter_notes + def create + render json: [Supporter.find(params[:supporter_id]).supporter_notes.create!(create_params.merge(user: current_user))] + end - # put /nonprofits/:nonprofit_id/supporters/:supporter_id/supporter_notes/:id - def update - params[:supporter_note][:user_id] ||= current_user && current_user.id - params[:supporter_note][:id] = params[:id] - render_json{ UpdateSupporterNotes.update(params[:supporter_note]) } - end + # put /nonprofits/:nonprofit_id/supporters/:supporter_id/supporter_notes/:id + def update + params[:supporter_note][:user_id] ||= current_user && current_user.id + params[:supporter_note][:id] = params[:id] + render_json { UpdateSupporterNotes.update(params[:supporter_note]) } + end - # delete /nonprofits/:nonprofit_id/supporters/:supporter_id/supporter_notes/:id - def destroy - render_json{ UpdateSupporterNotes.delete(params[:id]) } - end + # delete /nonprofits/:nonprofit_id/supporters/:supporter_id/supporter_notes/:id + def destroy + render_json { UpdateSupporterNotes.delete(params[:id]) } + end - private - def create_params - params.require(:supporter_note).permit(:content) + private + def create_params + params.require(:supporter_note).permit(:content) + end end end -end diff --git a/app/controllers/nonprofits/supporters_controller.rb b/app/controllers/nonprofits/supporters_controller.rb index 639ee8622..3d52855e1 100644 --- a/app/controllers/nonprofits/supporters_controller.rb +++ b/app/controllers/nonprofits/supporters_controller.rb @@ -1,125 +1,122 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits -class SupportersController < ApplicationController - include Controllers::NonprofitHelper - - before_action :authenticate_nonprofit_user!, except: [:new, :create] - - before_action :validate_allowed!, only: [:create] - rescue_from ::TempBlockError, with: :handle_temp_block_error - - - # get /nonprofit/:nonprofit_id/supporters - def index - @panels_layout = true - @nonprofit = current_nonprofit - respond_to do |format| - format.html - format.json do - render json: QuerySupporters.full_search(params[:nonprofit_id], params) - end - - format.csv do - file_date = Date.today.strftime("%m-%d-%Y") - supporters = QuerySupporters.for_export(params[:nonprofit_id], params) - send_data(Format::Csv.from_vectors(supporters), filename: "supporters-#{file_date}.csv") - end - end - end + class SupportersController < ApplicationController + include Controllers::NonprofitHelper + + before_action :authenticate_nonprofit_user!, except: [:new, :create] - def export - begin + before_action :validate_allowed!, only: [:create] + rescue_from ::TempBlockError, with: :handle_temp_block_error + + # get /nonprofit/:nonprofit_id/supporters + def index + @panels_layout = true @nonprofit = current_nonprofit - @user = current_user_id - ExportSupporters::initiate_export(@nonprofit.id, params, @user) - rescue => e - e + respond_to do |format| + format.html + format.json do + render json: QuerySupporters.full_search(params[:nonprofit_id], params) + end + + format.csv do + file_date = Date.today.strftime("%m-%d-%Y") + supporters = QuerySupporters.for_export(params[:nonprofit_id], params) + send_data(Format::Csv.from_vectors(supporters), filename: "supporters-#{file_date}.csv") + end + end end - if e.nil? - flash[:notice] = "Your export was successfully initiated and you'll be emailed at #{current_user.email} as soon as it's available. Feel free to use the site in the meantime." - render json: {}, status: :ok - else - render json: e, status: :ok + + def export + begin + @nonprofit = current_nonprofit + @user = current_user_id + ExportSupporters.initiate_export(@nonprofit.id, params, @user) + rescue => e + e + end + if e.nil? + flash[:notice] = "Your export was successfully initiated and you'll be emailed at #{current_user.email} as soon as it's available. Feel free to use the site in the meantime." + render json: {}, status: :ok + else + render json: e, status: :ok + end end - end - def index_metrics - render_json do - QuerySupporters.full_search_metrics(params[:nonprofit_id], params) + def index_metrics + render_json do + QuerySupporters.full_search_metrics(params[:nonprofit_id], params) + end end - end - def show - render json: {data: QuerySupporters.for_crm_profile(params[:nonprofit_id], [params[:id]]).first} - end + def show + render json: {data: QuerySupporters.for_crm_profile(params[:nonprofit_id], [params[:id]]).first} + end - def email_address - render json: Supporter.find(params[:id]).email - end + def email_address + render json: Supporter.find(params[:id]).email + end - def full_contact - fc = FullContactInfo.where("supporter_id= ?", params[:id]).first - if fc - render json: {full_contact: QueryFullContactInfos.fetch_associated_tables(fc.id )} - else - render json: {full_contact: nil} + def full_contact + fc = FullContactInfo.where("supporter_id= ?", params[:id]).first + if fc + render json: {full_contact: QueryFullContactInfos.fetch_associated_tables(fc.id)} + else + render json: {full_contact: nil} + end end - end - def info_card - render json: QuerySupporters.for_info_card(params[:id]) - end + def info_card + render json: QuerySupporters.for_info_card(params[:id]) + end - - # post /nonprofits/:nonprofit_id/supporters - def create - render_json{ InsertSupporter.create_or_update(params[:nonprofit_id], params[:supporter]) } - end - - # put /nonprofits/:nonprofit_id/supporters/:id - def update - @supporter = current_nonprofit.supporters.find(params[:id]) - json_saved UpdateSupporter.from_info(@supporter, params[:supporter]) - end - - def bulk_delete - if params[:selecting_all] - supporter_ids = QuerySupporters.full_filter_expr(current_nonprofit.id, params[:query]).select("supporters.id").execute.map{|h| h['id']} - else - supporter_ids = params[:supporter_ids]. map(&:to_i) + # post /nonprofits/:nonprofit_id/supporters + def create + render_json { InsertSupporter.create_or_update(params[:nonprofit_id], params[:supporter]) } end - render_json {UpdateSupporter.bulk_delete(current_nonprofit.id, supporter_ids ) } - end - # get /nonprofits/:nonprofit_id/supporters/merge_data - # returns the info required to merge two supporters - def merge_data - render json: QuerySupporters.merge_data(params[:ids]) - end + # put /nonprofits/:nonprofit_id/supporters/:id + def update + @supporter = current_nonprofit.supporters.find(params[:id]) + json_saved UpdateSupporter.from_info(@supporter, params[:supporter]) + end - # post /nonprofits/:nonprofit_id/supporters/merge - def merge - render JsonResp.new(params){|params| - requires(:supporter) - requires(:nonprofit_id).as_int - requires(:supporter_ids).as_array - }.when_valid{|params| - params[:supporter][:nonprofit_id] = params[:nonprofit_id] - MergeSupporters.selected(params[:supporter], params[:supporter_ids], params[:nonprofit_id], current_user.id) - } - end - - def validate_allowed! - raise(TempBlockError) if must_block? - end + def bulk_delete + supporter_ids = if params[:selecting_all] + QuerySupporters.full_filter_expr(current_nonprofit.id, params[:query]).select("supporters.id").execute.map { |h| h["id"] } + else + params[:supporter_ids].map(&:to_i) + end + render_json { UpdateSupporter.bulk_delete(current_nonprofit.id, supporter_ids) } + end - def handle_temp_block_error - render json: {error: "no"}, status: :unprocessable_entity - end + # get /nonprofits/:nonprofit_id/supporters/merge_data + # returns the info required to merge two supporters + def merge_data + render json: QuerySupporters.merge_data(params[:ids]) + end + + # post /nonprofits/:nonprofit_id/supporters/merge + def merge + render JsonResp.new(params) { |params| + requires(:supporter) + requires(:nonprofit_id).as_int + requires(:supporter_ids).as_array + }.when_valid { |params| + params[:supporter][:nonprofit_id] = params[:nonprofit_id] + MergeSupporters.selected(params[:supporter], params[:supporter_ids], params[:nonprofit_id], current_user.id) + } + end - # def new - # @nonprofit = current_nonprofit - # end + def validate_allowed! + raise(TempBlockError) if must_block? + end -end + def handle_temp_block_error + render json: {error: "no"}, status: :unprocessable_entity + end + + # def new + # @nonprofit = current_nonprofit + # end + end end diff --git a/app/controllers/nonprofits/tag_joins_controller.rb b/app/controllers/nonprofits/tag_joins_controller.rb index 92fa14b06..15f28caf9 100644 --- a/app/controllers/nonprofits/tag_joins_controller.rb +++ b/app/controllers/nonprofits/tag_joins_controller.rb @@ -1,47 +1,40 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Nonprofits - class TagJoinsController < ApplicationController - include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_user! + class TagJoinsController < ApplicationController + include Controllers::NonprofitHelper + before_action :authenticate_nonprofit_user! def index render_json do - {data: QuerySupporters.tag_joins(params['nonprofit_id'], params['supporter_id'])} + {data: QuerySupporters.tag_joins(params["nonprofit_id"], params["supporter_id"])} end end - # used for modify a single supporter's tags or a group of - # selected supporters' tags or all supporters' tags - def modify - - if params[:selecting_all] - supporter_ids = QuerySupporters.full_filter_expr(current_nonprofit.id, params[:query]).select("supporters.id").execute.map{|h| h['id']} + # used for modify a single supporter's tags or a group of + # selected supporters' tags or all supporters' tags + def modify + supporter_ids = if params[:selecting_all] + QuerySupporters.full_filter_expr(current_nonprofit.id, params[:query]).select("supporters.id").execute.map { |h| h["id"] } else - supporter_ids = params[:supporter_ids].map(&:to_i) + params[:supporter_ids].map(&:to_i) end - render InsertTagJoins.in_bulk(current_nonprofit.id, current_user.profile.id, supporter_ids, tag_modify_params) - - - - end - - def destroy - supporter = current_nonprofit.supporters.find(params[:supporter_id]) - supporter.tag_joins.find(params[:id]).destroy - render json: {}, status: :ok - end - + render InsertTagJoins.in_bulk(current_nonprofit.id, current_user.profile.id, supporter_ids, tag_modify_params) + end - private + def destroy + supporter = current_nonprofit.supporters.find(params[:supporter_id]) + supporter.tag_joins.find(params[:id]).destroy + render json: {}, status: :ok + end - def modify_params - params.permit(:selecting_all, query:[], supporter_ids:[], tags:[:tag_master_id, :selected]) - end + private - def tag_modify_params - modify_params.require(:tags) - end + def modify_params + params.permit(:selecting_all, query: [], supporter_ids: [], tags: [:tag_master_id, :selected]) + end - end + def tag_modify_params + modify_params.require(:tags) + end + end end - diff --git a/app/controllers/nonprofits/tag_masters_controller.rb b/app/controllers/nonprofits/tag_masters_controller.rb index 6abc8a7a6..17224de4a 100644 --- a/app/controllers/nonprofits/tag_masters_controller.rb +++ b/app/controllers/nonprofits/tag_masters_controller.rb @@ -5,14 +5,14 @@ class TagMastersController < ApplicationController before_action :authenticate_nonprofit_user! def index - render json: {data: - Qx.select('id', 'name', 'created_at') - .from('tag_masters') + render json: {data: + Qx.select("id", "name", "created_at") + .from("tag_masters") .where( - ['tag_masters.nonprofit_id = $id', id: current_nonprofit.id], - ["coalesce(deleted, FALSE) = FALSE"]) - .execute - } + ["tag_masters.nonprofit_id = $id", id: current_nonprofit.id], + ["coalesce(deleted, FALSE) = FALSE"] + ) + .execute} end def create @@ -25,7 +25,5 @@ def destroy tag_master.tag_joins.destroy_all render json: {}, status: :ok end - end end - diff --git a/app/controllers/nonprofits/trackings_controller.rb b/app/controllers/nonprofits/trackings_controller.rb index 208e64b73..c9969fa2c 100644 --- a/app/controllers/nonprofits/trackings_controller.rb +++ b/app/controllers/nonprofits/trackings_controller.rb @@ -3,10 +3,10 @@ module Nonprofits class TrackingsController < ApplicationController # POST /nonprofits/:nonprofit_id/tracking def create - render JsonResp.new(params){|data| + render JsonResp.new(params) { |data| requires(:donation_id).as_int optional(:utm_campaign, :utm_content, :utm_medium, :utm_source).as_string - }.when_valid{|data| + }.when_valid { |data| InsertTracking.create(params) } end diff --git a/app/controllers/nonprofits_controller.rb b/app/controllers/nonprofits_controller.rb index ac808509d..9d714a2bf 100755 --- a/app/controllers/nonprofits_controller.rb +++ b/app/controllers/nonprofits_controller.rb @@ -1,93 +1,92 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - class NonprofitsController < ApplicationController - include Controllers::NonprofitHelper +class NonprofitsController < ApplicationController + include Controllers::NonprofitHelper include Controllers::XFrame - helper_method :current_nonprofit_user? - before_action :authenticate_nonprofit_user!, only: [:dashboard, :dashboard_metrics, :dashboard_todos, :payment_history, :profile_todos, :recurring_donation_stats, :update] + helper_method :current_nonprofit_user? + before_action :authenticate_nonprofit_user!, only: [:dashboard, :dashboard_metrics, :dashboard_todos, :payment_history, :profile_todos, :recurring_donation_stats, :update] before_action :authenticate_super_admin!, only: [:destroy] after_action :allow_framing, only: [:donate, :btn] - - # get /nonprofits/:id - # get /:state_code/:city/:name - def show + # get /nonprofits/:id + # get /:state_code/:city/:name + def show if !current_nonprofit.published && !current_role?(:super_admin) - block_with_sign_in + block_with_sign_in return end - @nonprofit = current_nonprofit - @url = Format::Url.concat(root_url, @nonprofit.url) - @supporters = @nonprofit.supporters.not_deleted - @profiles = @nonprofit.profiles.order('total_raised DESC').limit(5).includes(:user).distinct + @nonprofit = current_nonprofit + @url = Format::Url.concat(root_url, @nonprofit.url) + @supporters = @nonprofit.supporters.not_deleted + @profiles = @nonprofit.profiles.order("total_raised DESC").limit(5).includes(:user).distinct - events = @nonprofit.events.not_deleted.order('start_datetime desc') - campaigns = @nonprofit.campaigns.not_deleted.not_a_child.order('created_at desc') + events = @nonprofit.events.not_deleted.order("start_datetime desc") + campaigns = @nonprofit.campaigns.not_deleted.not_a_child.order("created_at desc") - @events = events.upcoming - @any_past_events = events.past.any? - @active_campaigns = campaigns.active - @any_past_campaigns = campaigns.past.any? + @events = events.upcoming + @any_past_events = events.past.any? + @active_campaigns = campaigns.active + @any_past_campaigns = campaigns.past.any? - @nonprofit_background_image = FetchBackgroundImage.with_model(@nonprofit) + @nonprofit_background_image = FetchBackgroundImage.with_model(@nonprofit) - respond_to do |format| - format.html - format.json {render json: @nonprofit} - end - end + respond_to do |format| + format.html + format.json { render json: @nonprofit } + end + end def recurring_donation_stats render json: QueryRecurringDonations.overall_stats(current_nonprofit.id) end - def profile_todos - render json: FetchTodoStatus.for_profile(current_nonprofit) - end + def profile_todos + render json: FetchTodoStatus.for_profile(current_nonprofit) + end - def dashboard_todos - render json: FetchTodoStatus.for_dashboard(current_nonprofit) - end + def dashboard_todos + render json: FetchTodoStatus.for_dashboard(current_nonprofit) + end - def create + def create current_user ||= User.find(params[:user_id]) - json_saved Nonprofit.register(current_user, params[:nonprofit]) - end + json_saved Nonprofit.register(current_user, params[:nonprofit]) + end - def update - flash[:notice] = 'Update successful!' + def update + flash[:notice] = "Update successful!" current_nonprofit.update_attributes params[:nonprofit].except(:verification_status) - expire_action :action => :btn + expire_action action: :btn current_nonprofit.clear_cache - json_saved current_nonprofit - end + json_saved current_nonprofit + end def destroy - current_nonprofit.clear_cache + current_nonprofit.clear_cache current_nonprofit.destroy - flash[:notice] = 'Nonprofit removed' - render json: {} - end + flash[:notice] = "Nonprofit removed" + render json: {} + end # get /nonprofits/:id/donate def donate @nonprofit = current_nonprofit - @referer = params[:origin] || request.env['HTTP_REFERER'] + @referer = params[:origin] || request.env["HTTP_REFERER"] @campaign = current_nonprofit.campaigns.find_by_id(params[:campaign_id]) if params[:campaign_id] @countries_translations = countries_list(I18n.locale) - respond_to { |format| format.html{render layout: 'layouts/embed'} } + respond_to { |format| format.html { render layout: "layouts/embed" } } end - def btn - @nonprofit = current_nonprofit - respond_to { |format| format.html{render layout: 'layouts/btn'} } - end + def btn + @nonprofit = current_nonprofit + respond_to { |format| format.html { render layout: "layouts/btn" } } + end # get /nonprofits/:id/supporter_form def supporter_form - @nonprofit = current_nonprofit - respond_to { |format| format.html{render layout: 'layouts/embed'} } + @nonprofit = current_nonprofit + respond_to { |format| format.html { render layout: "layouts/embed" } } end # post /nonprofits/:id/supporter_with_tag @@ -96,22 +95,22 @@ def custom_supporter render json: InsertSupporter.with_tags_and_fields(@nonprofit.id, params[:supporter]) end - def dashboard + def dashboard @nonprofit = current_nonprofit @can_make_payouts = @nonprofit.can_make_payouts? @verification_status = @nonprofit&.stripe_account&.verification_status || :unverified - @deadline = @nonprofit&.stripe_account&.deadline && @nonprofit.stripe_account.deadline.in_time_zone(@nonprofit.timezone).strftime('%B %e, %Y at %l:%M:%S %p') - respond_to { |format| format.html } - end + @deadline = @nonprofit&.stripe_account&.deadline && @nonprofit.stripe_account.deadline.in_time_zone(@nonprofit.timezone).strftime("%B %e, %Y at %l:%M:%S %p") + respond_to { |format| format.html } + end - def dashboard_metrics - render json: { data: NonprofitMetrics.all_metrics(current_nonprofit.id) } - end + def dashboard_metrics + render json: {data: NonprofitMetrics.all_metrics(current_nonprofit.id)} + end - def payment_history + def payment_history render json: NonprofitMetrics.payment_history(params) - end + end def search render json: QueryNonprofits.by_search_string(params[:npo_name]) @@ -131,13 +130,12 @@ def countries_list(locale) all_countries = ISO3166::Country.translations(locale) if Settings.intntl.all_countries - countries = all_countries.select{ |code, name| Settings.intntl.all_countries.include? code } - countries = countries.map{ |code, name| [code.upcase, name] }.sort{ |a, b| a[1] <=> b[1] } - countries.push([Settings.intntl.other_country.upcase, I18n.t('nonprofits.donate.info.supporter.other_country')]) if Settings.intntl.other_country + countries = all_countries.select { |code, name| Settings.intntl.all_countries.include? code } + countries = countries.map { |code, name| [code.upcase, name] }.sort_by { |a| a[1] } + countries.push([Settings.intntl.other_country.upcase, I18n.t("nonprofits.donate.info.supporter.other_country")]) if Settings.intntl.other_country countries else - all_countries.map{ |code, name| [code.upcase, name] }.sort{ |a, b| a[1] <=> b[1] } + all_countries.map { |code, name| [code.upcase, name] }.sort_by { |a| a[1] } end end - end diff --git a/app/controllers/onboard_controller.rb b/app/controllers/onboard_controller.rb index 7e11316cb..8b1cb4dec 100644 --- a/app/controllers/onboard_controller.rb +++ b/app/controllers/onboard_controller.rb @@ -1,6 +1,6 @@ class OnboardController < ApplicationController - layout 'layouts/apified' + layout "layouts/apified" def index - @theme = 'minimal' + @theme = "minimal" end end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 0f01490c7..6998de843 100755 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -1,30 +1,29 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ProfilesController < ApplicationController - helper_method :authenticate_profile_owner! - before_action :authenticate_profile_owner!, only: [:update, :fundraisers, :donations_history] + before_action :authenticate_profile_owner!, only: [:update, :fundraisers, :donations_history] - # get /profiles/:id - # public profile - def show - @profile = Profile.find(params[:id]) - @profile_nonprofits = Psql.execute(Qexpr.new.select("DISTINCT nonprofits.*").from(:nonprofits).join(:supporters, "supporters.nonprofit_id=nonprofits.id AND supporters.profile_id=#{@profile.id}")) + # get /profiles/:id + # public profile + def show + @profile = Profile.find(params[:id]) + @profile_nonprofits = Psql.execute(Qexpr.new.select("DISTINCT nonprofits.*").from(:nonprofits).join(:supporters, "supporters.nonprofit_id=nonprofits.id AND supporters.profile_id=#{@profile.id}")) @campaigns = @profile.campaigns.published.includes(:nonprofit) - if @profile.anonymous? && current_user_id != @profile.user_id && !current_role?(:super_admin) - flash[:notice] = 'That user does not have a public profile.' - redirect_to(root_url) - return - end - end + if @profile.anonymous? && current_user_id != @profile.user_id && !current_role?(:super_admin) + flash[:notice] = "That user does not have a public profile." + redirect_to(root_url) + nil + end + end - # get /profiles/:id/donations_history - def donations_history + # get /profiles/:id/donations_history + def donations_history validate - @profile = Profile.find(params[:id]) - @recurring_donations = @profile.recurring_donations.where(:active => true).includes(:nonprofit) - @donations = @profile.donations.includes(:nonprofit) - end + @profile = Profile.find(params[:id]) + @recurring_donations = @profile.recurring_donations.where(active: true).includes(:nonprofit) + @donations = @profile.donations.includes(:nonprofit) + end # get /profiles/:id/fundraisers def fundraisers @@ -36,28 +35,28 @@ def fundraisers # get /profiles/:id/events def events - render json: QueryEventMetrics.for_listings('profile', params[:id], params) + render json: QueryEventMetrics.for_listings("profile", params[:id], params) end - # put /profiles/:id - def update - if current_role?(:super_admin) # can update other profiles - @profile = Profile.find(params[:id]) + # put /profiles/:id + def update + @profile = if current_role?(:super_admin) # can update other profiles + Profile.find(params[:id]) else - @profile = current_user.profile + current_user.profile end - @profile.update_attributes(params[:profile]) - json_saved @profile, 'Profile updated' - end + @profile.update_attributes(params[:profile]) + json_saved @profile, "Profile updated" + end private - def authenticate_profile_owner!() - if (!current_role?(:super_associate) && + def authenticate_profile_owner! + if !current_role?(:super_associate) && !current_role?(:super_admin) && (!current_user || !current_user.profile || - current_user.profile.id != params[:id].to_i)) + current_user.profile.id != params[:id].to_i) block_with_sign_in end end diff --git a/app/controllers/recurring_donations_controller.rb b/app/controllers/recurring_donations_controller.rb index f8bfd5b28..44ce1e09d 100644 --- a/app/controllers/recurring_donations_controller.rb +++ b/app/controllers/recurring_donations_controller.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class RecurringDonationsController < ApplicationController - def edit @data = QueryRecurringDonations.fetch_for_edit params[:id] - - if @data && params[:t] == @data['recurring_donation']['edit_token'] + + if @data && params[:t] == @data["recurring_donation"]["edit_token"] @nonprofit = RecurringDonation.find(params[:id]).nonprofit - @data['change_amount_suggestions'] = CalculateSuggestedAmounts.calculate(@data['recurring_donation']['amount']) - @data['miscellaneous_np_info'] = FetchMiscellaneousNpInfo.fetch(@data['nonprofit']['id']) - if @data['miscellaneous_np_info']['donate_again_url'].blank? - @data['miscellaneous_np_info']['donate_again_url'] = url_for(:controller => :nonprofits, :action=> :show, :id => @data['nonprofit']['id'], :only_path => false) + @data["change_amount_suggestions"] = CalculateSuggestedAmounts.calculate(@data["recurring_donation"]["amount"]) + @data["miscellaneous_np_info"] = FetchMiscellaneousNpInfo.fetch(@data["nonprofit"]["id"]) + if @data["miscellaneous_np_info"]["donate_again_url"].blank? + @data["miscellaneous_np_info"]["donate_again_url"] = url_for(controller: :nonprofits, action: :show, id: @data["nonprofit"]["id"], only_path: false) end respond_to do |format| format.html @@ -22,50 +21,48 @@ def edit def destroy @data = QueryRecurringDonations.fetch_for_edit params[:id] - if params[:edit_token] != @data['recurring_donation']['edit_token'] - render json: {error: 'Invalid token'}, status: :unprocessable_entity + if params[:edit_token] != @data["recurring_donation"]["edit_token"] + render json: {error: "Invalid token"}, status: :unprocessable_entity else - updated = UpdateRecurringDonations.cancel(params[:id], current_user ? current_user.email : @data['supporter']['email']) + updated = UpdateRecurringDonations.cancel(params[:id], current_user ? current_user.email : @data["supporter"]["email"]) render json: updated end end def update data = QueryRecurringDonations.fetch_for_edit params[:id] - if data && params[:edit_token] == data['recurring_donation']['edit_token'] - data['supporter'] = UpdateSupporter.general_info(params[:supporter][:id], params[:supporter]) if params[:supporter] - data['recurring_donation'] ||= {} - data['recurring_donation'] = UpdateRecurringDonations.update_card_id(data['recurring_donation'], params[:token]) if params[:token] - data['recurring_donation'] = UpdateRecurringDonations.update_paydate(data['recurring_donation'], params[:paydate]) if params[:paydate] + if data && params[:edit_token] == data["recurring_donation"]["edit_token"] + data["supporter"] = UpdateSupporter.general_info(params[:supporter][:id], params[:supporter]) if params[:supporter] + data["recurring_donation"] ||= {} + data["recurring_donation"] = UpdateRecurringDonations.update_card_id(data["recurring_donation"], params[:token]) if params[:token] + data["recurring_donation"] = UpdateRecurringDonations.update_paydate(data["recurring_donation"], params[:paydate]) if params[:paydate] render json: data, status: data.is_a?(ValidationError) ? :unprocessable_entity : :ok else - render json: {error: 'Invalid token'}, status: :unprocessable_entity + render json: {error: "Invalid token"}, status: :unprocessable_entity end end def update_amount - rd = RecurringDonation.where('id = ?', params[:id]).first - if rd && params[:edit_token] == rd['edit_token'] + rd = RecurringDonation.where("id = ?", params[:id]).first + if rd && params[:edit_token] == rd["edit_token"] begin - amount_response = UpdateRecurringDonations.update_amount(rd, params[:token], params[:amount], params[:fee_covered]) - flash[:notice] = "Your recurring donation amount has been successfully changed to #{print_currency(amount_response.amount, '$')}" + amount_response = UpdateRecurringDonations.update_amount(rd, params[:token], params[:amount], params[:fee_covered]) + flash[:notice] = "Your recurring donation amount has been successfully changed to #{print_currency(amount_response.amount, "$")}" render_json { amount_response } rescue => e render_json { raise e } end else - render json: {error: 'Invalid token'}, status: :unprocessable_entity + render json: {error: "Invalid token"}, status: :unprocessable_entity end end private - def print_currency(cents, unit="EUR", sign=true) - - dollars = cents.to_f / 100.0 - dollars = view_context.number_to_currency(dollars, :unit => "#{unit}", :precision => (dollars.round == dollars) ? 0 : 2) - dollars = dollars[1..-1] if !sign - dollars - end - + def print_currency(cents, unit = "EUR", sign = true) + dollars = cents.to_f / 100.0 + dollars = view_context.number_to_currency(dollars, unit: "#{unit}", precision: (dollars.round == dollars) ? 0 : 2) + dollars = dollars[1..-1] if !sign + dollars + end end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index ff211e3b3..ec69d5170 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -1,23 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class RolesController < ApplicationController - include Controllers::NonprofitHelper + include Controllers::NonprofitHelper - before_action :authenticate_nonprofit_admin! + before_action :authenticate_nonprofit_admin! - def create - role = Role.create_for_nonprofit(params[:role][:name].to_sym, params[:role][:email], FetchNonprofit.with_params(params)) - json_saved role, "User successfully added!" - end + def create + role = Role.create_for_nonprofit(params[:role][:name].to_sym, params[:role][:email], FetchNonprofit.with_params(params)) + json_saved role, "User successfully added!" + end - def destroy - role = Role.find(params[:id]) - roles = role.user.roles.where(host_id: params[:nonprofit_id], name: role.name) - unless roles.empty? - roles.destroy_all - flash[:notice] = 'User successfully removed' - render json: {} - else - render json: {:error => "We couldn't find that admin"}, :status => :unprocessable_entity - end - end + def destroy + role = Role.find(params[:id]) + roles = role.user.roles.where(host_id: params[:nonprofit_id], name: role.name) + if roles.empty? + render json: {error: "We couldn't find that admin"}, status: :unprocessable_entity + else + roles.destroy_all + flash[:notice] = "User successfully removed" + render json: {} + end + end end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index 0ee1df012..57ba89f4b 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -1,33 +1,31 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SettingsController < ApplicationController - include Controllers::NonprofitHelper + include Controllers::NonprofitHelper - helper_method :current_nonprofit_user? - before_action :authenticate_user! + helper_method :current_nonprofit_user? + before_action :authenticate_user! - def index - if current_role?(:super_admin) && params[:nonprofit_id] - @nonprofit = Nonprofit.find(params[:nonprofit_id]) - elsif current_role?([:nonprofit_admin, :nonprofit_associate]) - @nonprofit = administered_nonprofit - end + def index + if current_role?(:super_admin) && params[:nonprofit_id] + @nonprofit = Nonprofit.find(params[:nonprofit_id]) + elsif current_role?([:nonprofit_admin, :nonprofit_associate]) + @nonprofit = administered_nonprofit + end - if current_role?(:super_admin) && params[:user_id] - @user = User.find_by_id(params[:user_id]) + @user = if current_role?(:super_admin) && params[:user_id] + User.find_by_id(params[:user_id]) elsif current_role?(:super_admin) && params[:user_email] - @user = User.find_by_email(params[:user_email]) + User.find_by_email(params[:user_email]) else - @user = current_user + current_user end - @profile = @user.profile - - if @nonprofit - @miscellaneous_np_info = FetchMiscellaneousNpInfo.fetch(@nonprofit.id) + @profile = @user.profile - @steps_to_payout = @nonprofit.steps_to_payout - end - - end + if @nonprofit + @miscellaneous_np_info = FetchMiscellaneousNpInfo.fetch(@nonprofit.id) + @steps_to_payout = @nonprofit.steps_to_payout + end + end end diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb index da9b30599..521a568e8 100644 --- a/app/controllers/static_controller.rb +++ b/app/controllers/static_controller.rb @@ -1,26 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class StaticController < ApplicationController - layout 'layouts/static' + layout "layouts/static" def terms_and_privacy - @theme = 'minimal' + @theme = "minimal" end def ccs - ccs_method = !Settings.ccs ? 'local_tar_gz' : Settings.ccs.ccs_method - if (ccs_method == 'local_tar_gz') - temp_file = "#{Rails.root}/tmp/#{Time.current.to_i}.tar.gz" + ccs_method = (!Settings.ccs) ? "local_tar_gz" : Settings.ccs.ccs_method + if ccs_method == "local_tar_gz" + temp_file = "#{Rails.root.join("tmp/#{Time.current.to_i}.tar.gz")}" result = Kernel.system("git archive --format=tar.gz -o #{temp_file} HEAD") if result - send_file(temp_file, :type => "application/gzip") + send_file(temp_file, type: "application/gzip") else head 500 end - elsif (ccs_method == 'github') - git_hash = File.read("#{Rails.root}/CCS_HASH") + elsif ccs_method == "github" + git_hash = File.read("#{Rails.root.join("CCS_HASH")}") redirect_to "https://github.com/#{Settings.ccs.options.account}/#{Settings.ccs.options.repo}/tree/#{git_hash}", allow_other_host: true end - end end diff --git a/app/controllers/super_admins_controller.rb b/app/controllers/super_admins_controller.rb index 84ed07a56..f77323b74 100644 --- a/app/controllers/super_admins_controller.rb +++ b/app/controllers/super_admins_controller.rb @@ -4,7 +4,7 @@ class SuperAdminsController < ApplicationController before_action :authenticate_super_associate! - def index + def index end def search_nonprofits @@ -15,22 +15,22 @@ def search_profiles render json: QueryProfiles.for_admin(params) end - def search_fullcontact + def search_fullcontact begin result = FullContact.person(email: params[:search]) - rescue Exception => e - result = '' + rescue Exception + result = "" end render json: [result] end def resend_user_confirmation ParamValidation.new(params || {}, { - profile_id: {:required => true, is_integer: true} + profile_id: {required: true, is_integer: true} }) - profile = Profile.includes(:user).where('id = ?', params[:profile_id]).first - unless (profile.user) + profile = Profile.includes(:user).where("id = ?", params[:profile_id]).first + unless profile.user raise ArgumentError.new("#{params[:profile_id]} is a profile without a valid user") end @@ -40,24 +40,23 @@ def resend_user_confirmation end def recurring_donations_without_cards - odd_donations = QueryRecurringDonations::recurring_donations_without_cards + odd_donations = QueryRecurringDonations.recurring_donations_without_cards respond_to do |format| format.html format.csv do csv_out = CSV.generate { |csv| - csv << ['supporter id', 'recurring donation id', 'rd created date', 'rd modified', 'donation id', 'donation card id', - 'edit_token', 'nonprofit id', - 'last charge succeeded id', 'last charge succeeded created at', 'last charge attempted id', 'last charge attempted created at', 'amount'] + csv << ["supporter id", "recurring donation id", "rd created date", "rd modified", "donation id", "donation card id", + "edit_token", "nonprofit id", + "last charge succeeded id", "last charge succeeded created at", "last charge attempted id", "last charge attempted created at", "amount"] odd_donations.each { |rd| csv << [rd.supporter.id, rd.id, rd.created_at, rd.updated_at, rd.donation.id, rd.donation.card_id, rd.edit_token, rd.nonprofit.id, - rd.most_recent_paid_charge.id, rd.most_recent_paid_charge.created_at, rd.most_recent_charge.id, rd.most_recent_charge.created_at, - rd.amount] + rd.most_recent_paid_charge.id, rd.most_recent_paid_charge.created_at, rd.most_recent_charge.id, rd.most_recent_charge.created_at, + rd.amount] } } - - send_data(csv_out, filename: "recurring_donations_without_cards-#{Time.now.to_date()}.csv") + send_data(csv_out, filename: "recurring_donations_without_cards-#{Time.now.to_date}.csv") end end end @@ -67,15 +66,11 @@ def export_supporters_with_rds ids = params[:ids] results = QuerySupporters.for_export(np, {ids: ids}) results[0].push("Management URLS") - results.drop(1).each {|row| - rds = Supporter.includes(:recurring_donations).find(row.last).recurring_donations.select{|rd| rd.active}.map{|rd| "* #{root_url}recurring_donations/#{rd.id}/edit?t=#{rd.edit_token}"}.join("\n") + results.drop(1).each { |row| + rds = Supporter.includes(:recurring_donations).find(row.last).recurring_donations.select { |rd| rd.active }.map { |rd| "* #{root_url}recurring_donations/#{rd.id}/edit?t=#{rd.edit_token}" }.join("\n") row.push(rds) } - send_data(Format::Csv.from_vectors(results), filename: "supporters_with_multiple_donations.csv") end - - end - diff --git a/app/controllers/ticket_levels_controller.rb b/app/controllers/ticket_levels_controller.rb index 3e12ff56e..3fe7a29eb 100644 --- a/app/controllers/ticket_levels_controller.rb +++ b/app/controllers/ticket_levels_controller.rb @@ -1,44 +1,43 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TicketLevelsController < ApplicationController - include Controllers::EventHelper + include Controllers::EventHelper - before_action :authenticate_event_editor!, :except => [:index, :show] + before_action :authenticate_event_editor!, except: [:index, :show] - def index + def index ev_id = current_event.id render json: {data: QueryTicketLevels.with_event_id(ev_id, current_role?(:event_editor, ev_id) || current_role?(:super_admin) || current_role?(:nonprofit_admin, current_event.nonprofit_id))} - end + end - def show - render json: current_ticket_level - end + def show + render json: current_ticket_level + end - def create - ticket_level = current_event.ticket_levels.create params[:ticket_level] - json_saved ticket_level, 'Ticket level created!' - end + def create + ticket_level = current_event.ticket_levels.create params[:ticket_level] + json_saved ticket_level, "Ticket level created!" + end - def update - current_ticket_level.update_attributes params[:ticket_level] - json_saved current_ticket_level, 'Ticket level updated' - end + def update + current_ticket_level.update_attributes params[:ticket_level] + json_saved current_ticket_level, "Ticket level updated" + end # put /nonprofits/:nonprofit_id/events/:event_id/ticket_levels/update_order # Pass in {data: [{id: 1, order: 1}]} def update_order - updated_ticket_levels = UpdateOrder.with_data('ticket_levels', params[:data]) + updated_ticket_levels = UpdateOrder.with_data("ticket_levels", params[:data]) render json: updated_ticket_levels end def destroy - current_ticket_level.destroy - render json: {} - end - -private + current_ticket_level.destroy + render json: {} + end - def current_ticket_level - @ticket_level ||= current_event.ticket_levels.find params[:id] - end + private + def current_ticket_level + @ticket_level ||= current_event.ticket_levels.find params[:id] + end end diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb index 407961b04..4ff2c69c1 100644 --- a/app/controllers/tickets_controller.rb +++ b/app/controllers/tickets_controller.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TicketsController < ApplicationController - include Controllers::EventHelper + include Controllers::EventHelper - helper_method :current_event_admin?, :current_event_editor? - before_action :authenticate_event_editor!, :except => [:create, :add_note] + helper_method :current_event_admin?, :current_event_editor? + before_action :authenticate_event_editor!, except: [:create, :add_note] before_action :authenticate_nonprofit_user!, only: [:delete_card_for_ticket] - # post /nonprofits/:nonprofit_id/events/:event_id/tickets - def create - authenticate_event_editor! if params[:kind] == 'offsite' + # post /nonprofits/:nonprofit_id/events/:event_id/tickets + def create + authenticate_event_editor! if params[:kind] == "offsite" render_json do params[:current_user] = current_user InsertTickets.create(params) @@ -18,29 +18,29 @@ def create def update params[:ticket][:ticket_id] = params[:id] params[:ticket][:event_id] = params[:event_id] - render_json{ UpdateTickets.update(params[:ticket], current_user) } + render_json { UpdateTickets.update(params[:ticket], current_user) } end # Attendees dashboard - # get /nonprofits/:nonprofit_id/events/:event_id/tickets - def index - @panels_layout = true - @nonprofit = current_nonprofit - @event = current_event - respond_to do |format| - format.html + # get /nonprofits/:nonprofit_id/events/:event_id/tickets + def index + @panels_layout = true + @nonprofit = current_nonprofit + @event = current_event + respond_to do |format| + format.html format.csv do - file_date = Date.today.strftime("%m-%d-%Y") - filename = "tickets-#{file_date}" + file_date = Date.today.strftime("%m-%d-%Y") + filename = "tickets-#{file_date}" @tickets = QueryTickets.for_export(@event.id, params) - send_data(Format::Csv.from_vectors(@tickets), filename: "#{filename}.csv") + send_data(Format::Csv.from_vectors(@tickets), filename: "#{filename}.csv") end - format.json do + format.json do render json: QueryTickets.attendees_list(@event.id, params) - end - end - end + end + end + end # PUT nonprofits/:nonprofit_id/events/:event_id/tickets/:id/add_note def add_note diff --git a/app/controllers/users/confirmations_controller.rb b/app/controllers/users/confirmations_controller.rb index 546aec90b..85848014f 100644 --- a/app/controllers/users/confirmations_controller.rb +++ b/app/controllers/users/confirmations_controller.rb @@ -1,40 +1,39 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Users::ConfirmationsController < Devise::ConfirmationsController - # get /confirm - def show - @user = User.confirm_by_token(params[:confirmation_token]) + # get /confirm + def show + @user = User.confirm_by_token(params[:confirmation_token]) - if !@user.auto_generated || !@user.valid? - flash[:notice] = "We successfully confirmed your account" - redirect_to session[:donor_signup_url] || root_url - else + if !@user.auto_generated || !@user.valid? + flash[:notice] = "We successfully confirmed your account" + redirect_to session[:donor_signup_url] || root_url + else respond_to do |format| format.html end - end - end + end + end def exists render json: User.find_by_email(params[:email]) end - # post /confirm - # set account password - def confirm - @user = User.find(params[:id]) + # post /confirm + # set account password + def confirm + @user = User.find(params[:id]) - if @user.valid? && @user.update_attributes(params[:user].except(:confirmation_token)) - flash[:notice] = "Your account is all set!" - sign_in @user - redirect_to session[:donor_signup_url] || root_url - else - session[:donor_signup_url] || root_url - #render :action => "show", :layout => 'layouts/embed' - end - end + if @user.valid? && @user.update_attributes(params[:user].except(:confirmation_token)) + flash[:notice] = "Your account is all set!" + sign_in @user + redirect_to session[:donor_signup_url] || root_url + else + session[:donor_signup_url] || root_url + # render :action => "show", :layout => 'layouts/embed' + end + end def is_confirmed render json: {is_confirmed: User.find(params[:user_id]).confirmed?} end - end diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index 708527515..00bbb6293 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Users::RegistrationsController < Devise::RegistrationsController respond_to :html, :json - + before_action :verify_via_recaptcha!, only: [:create] rescue_from ::Recaptcha::RecaptchaError, with: :handle_recaptcha_failure @@ -12,12 +12,12 @@ def new # this endpoint only creates donor users def create - user = User.register_donor!({referer: session[:referer_id]}.merge(params[:user].to_deprecated_h) ) + user = User.register_donor!({referer: session[:referer_id]}.merge(params[:user].to_deprecated_h)) if user.save sign_in user - render :json => user + render json: user else - render :json => user.errors.full_messages, :status => :unprocessable_entity + render json: user.errors.full_messages, status: :unprocessable_entity clean_up_passwords(user) end end @@ -36,41 +36,39 @@ def update errs = current_user.errors.full_messages else success = false - errs = {:password => :incorrect} + errs = {password: :incorrect} end if success - if params[:user][:email].present? - flash[:notice] = 'We need to confirm your new email address. Check your inbox for a confirmation link.' + flash[:notice] = if params[:user][:email].present? + "We need to confirm your new email address. Check your inbox for a confirmation link." else - flash[:notice] = 'Account updated!' + "Account updated!" end - sign_in(current_user, :bypass => true) - render :json => current_user + sign_in(current_user, bypass: true) + render json: current_user else - render :json => {:errors => errs}, :status => :unprocessable_entity + render json: {errors: errs}, status: :unprocessable_entity end end - private + def verify_via_recaptcha! - begin - verify_recaptcha!(action: 'create_user', minimum_score: ENV['MINIMUM_RECAPTCHA_SCORE'].to_f) - rescue ::Recaptcha::RecaptchaError => e - failure_details = { - params: params, - action: 'create_user', - minimum_score_required: ENV['MINIMUM_RECAPTCHA_SCORE'], - recaptcha_result: recaptcha_reply, - recaptcha_value: params['g-recaptcha-response'] - } - failure = RecaptchaRejection.new - failure.details = failure_details - failure.save! - raise e - end + verify_recaptcha!(action: "create_user", minimum_score: ENV["MINIMUM_RECAPTCHA_SCORE"].to_f) + rescue ::Recaptcha::RecaptchaError => e + failure_details = { + params: params, + action: "create_user", + minimum_score_required: ENV["MINIMUM_RECAPTCHA_SCORE"], + recaptcha_result: recaptcha_reply, + recaptcha_value: params["g-recaptcha-response"] + } + failure = RecaptchaRejection.new + failure.details = failure_details + failure.save! + raise e end def handle_recaptcha_failure diff --git a/app/controllers/users/sessions_controller.rb b/app/controllers/users/sessions_controller.rb index c8e101cfe..8664f27e2 100644 --- a/app/controllers/users/sessions_controller.rb +++ b/app/controllers/users/sessions_controller.rb @@ -1,41 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Users::SessionsController < Devise::SessionsController - include ::Controllers::XFrame - - layout 'layouts/apified', only: :new - - after_action :prevent_framing - - def new - @theme = 'minimal' + include ::Controllers::XFrame + + layout "layouts/apified", only: :new + + after_action :prevent_framing + + def new + @theme = "minimal" super end - def create - @theme = 'minimal' + def create + @theme = "minimal" - respond_to do |format| - format.json { - self.resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new") - sign_in(resource_name, resource) - render :status => 200, :json => { :status => "Success" } - } - end - end + respond_to do |format| + format.json { + self.resource = warden.authenticate!(scope: resource_name, recall: "#{controller_path}#new") + sign_in(resource_name, resource) + render status: 200, json: {status: "Success"} + } + end + end - - # post /users/confirm_auth - # A simple action to confirm an entered password for a user who is already signed in - def confirm_auth - if current_user.valid_password?(params[:password]) - tok = SecureRandom.uuid - session[:pw_token] = tok - session[:pw_timestamp] = Time.current.to_s - render json: {token: tok}, status: :ok - else - render json: ["Incorrect password. Please enter your #{Settings.general.name} password."], status: :unprocessable_entity - end + # post /users/confirm_auth + # A simple action to confirm an entered password for a user who is already signed in + def confirm_auth + if current_user.valid_password?(params[:password]) + tok = SecureRandom.uuid + session[:pw_token] = tok + session[:pw_timestamp] = Time.current.to_s + render json: {token: tok}, status: :ok + else + render json: ["Incorrect password. Please enter your #{Settings.general.name} password."], status: :unprocessable_entity + end end - end - diff --git a/app/controllers/webhooks/stripe_controller.rb b/app/controllers/webhooks/stripe_controller.rb index 59d24b99c..1a214351c 100644 --- a/app/controllers/webhooks/stripe_controller.rb +++ b/app/controllers/webhooks/stripe_controller.rb @@ -6,36 +6,33 @@ class StripeController < ApplicationController rescue_from Stripe::SignatureVerificationError, with: :signature_invalid_error def receive - sig_header = request.headers['HTTP_STRIPE_SIGNATURE'] - event = nil - payload = JSON.parse(request.raw_post) + sig_header = request.headers["HTTP_STRIPE_SIGNATURE"] + JSON.parse(request.raw_post) event = Stripe::Webhook.construct_event( - request.raw_post, sig_header, ENV['STRIPE_WEBHOOK_SECRET'] + request.raw_post, sig_header, ENV["STRIPE_WEBHOOK_SECRET"] ) if ENV["RAILS_ENV"] != "production" || event.livemode StripeEvent.handle(event) end - render json:{}, status: 200 + render json: {}, status: 200 end def receive_connect - sig_header = request.headers['HTTP_STRIPE_SIGNATURE'] - event = nil - payload = JSON.parse(request.raw_post) + sig_header = request.headers["HTTP_STRIPE_SIGNATURE"] + JSON.parse(request.raw_post) event = Stripe::Webhook.construct_event( - request.raw_post, sig_header, ENV['STRIPE_CONNECT_WEBHOOK_SECRET'] + request.raw_post, sig_header, ENV["STRIPE_CONNECT_WEBHOOK_SECRET"] ) if ENV["RAILS_ENV"] != "production" || event.livemode StripeEvent.handle(event) end - render json:{}, status: 200 + render json: {}, status: 200 end - + protected - protected def invalid_payload_error(exception) render json: {error: "Invalid payload", details: exception.to_s, backtrace: exception.backtrace}, status: 400 end diff --git a/app/forms/register_nonprofit_form/nonprofit_form.rb b/app/forms/register_nonprofit_form/nonprofit_form.rb index e66048592..6ea529b03 100644 --- a/app/forms/register_nonprofit_form/nonprofit_form.rb +++ b/app/forms/register_nonprofit_form/nonprofit_form.rb @@ -11,7 +11,7 @@ class RegisterNonprofitForm::NonprofitForm < ApplicationForm :zip_code validates :zip_code, presence: true - validates :website, format: {with: URI.regexp}, if: proc { |form| form.website.present? } + validates :website, format: {with: URI::DEFAULT_PARSER.make_regexp}, if: proc { |form| form.website.present? } # validates :email, format: {with: URI::MailTo::EMAIL_REGEXP }, if: Proc.new { |form| form.email.present? } def initialize(attributes = {}) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0c54eac1a..37b17aa2c 100755 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,59 +1,56 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ApplicationHelper - - def resource_name - :user - end - - def resource - @resource ||= User.new - end - - def devise_mapping - @devise_mapping ||= Devise.mappings[:user] - end - - def print_currency(cents, unit="EUR", sign=true) - - dollars = cents.to_f / 100.0 - dollars = number_to_currency(dollars, :unit => "#{unit}", :precision => (dollars.round == dollars) ? 0 : 2) - dollars = dollars[1..-1] if !sign - dollars - end - - def print_percent(rate) - (rate.to_f * 100).round(2) - end - - ## Dates - - def simple_date date_object, timezone=nil - return '' if date_object.nil? - date_object = date_object.in_time_zone(timezone) if timezone - date_object.strftime("%m/%d/%Y") - end - - def readable_date date_object - date_object.strftime("%B %d, %Y") - end - - def date_and_time date_object, timezone=nil - date_object = date_object.in_time_zone(timezone) if timezone - date_object.strftime("%m/%d/%Y %I:%M%P (%Z)") - end - - def us_states - [ ['Alabama', 'AL'], ['Alaska', 'AK'], ['Arizona', 'AZ'], ['Arkansas', 'AR'], ['California', 'CA'], ['Colorado', 'CO'], ['Connecticut', 'CT'], ['Delaware', 'DE'], ['District of Columbia', 'DC'], ['Florida', 'FL'], ['Georgia', 'GA'], ['Hawaii', 'HI'], ['Idaho', 'ID'], ['Illinois', 'IL'], ['Indiana', 'IN'], ['Iowa', 'IA'], ['Kansas', 'KS'], ['Kentucky', 'KY'], ['Louisiana', 'LA'], ['Maine', 'ME'], ['Maryland', 'MD'], ['Massachusetts', 'MA'], ['Michigan', 'MI'], ['Minnesota', 'MN'], ['Mississippi', 'MS'], ['Missouri', 'MO'], ['Montana', 'MT'], ['Nebraska', 'NE'], ['Nevada', 'NV'], ['New Hampshire', 'NH'], ['New Jersey', 'NJ'], ['New Mexico', 'NM'], ['New York', 'NY'], ['North Carolina', 'NC'], ['North Dakota', 'ND'], ['Ohio', 'OH'], ['Oklahoma', 'OK'], ['Oregon', 'OR'], ['Pennsylvania', 'PA'], ['Puerto Rico', 'PR'], ['Rhode Island', 'RI'], ['South Carolina', 'SC'], ['South Dakota', 'SD'], ['Tennessee', 'TN'], ['Texas', 'TX'], ['Utah', 'UT'], ['Vermont', 'VT'], ['Virginia', 'VA'], ['Washington', 'WA'], ['West Virginia', 'WV'], ['Wisconsin', 'WI'], ['Wyoming', 'WY'] ] - end - - # Prepend 'http://' if it is not present in a given url - # Used for linking to nonprofit-provided website - def add_http url - if url[/^http:\/\//] || url[/^https:\/\//] - url - else - 'http://' + url - end - end - + def resource_name + :user + end + + def resource + @resource ||= User.new + end + + def devise_mapping + @devise_mapping ||= Devise.mappings[:user] + end + + def print_currency(cents, unit = "EUR", sign = true) + dollars = cents.to_f / 100.0 + dollars = number_to_currency(dollars, unit: "#{unit}", precision: (dollars.round == dollars) ? 0 : 2) + dollars = dollars[1..-1] if !sign + dollars + end + + def print_percent(rate) + (rate.to_f * 100).round(2) + end + + ## Dates + + def simple_date date_object, timezone = nil + return "" if date_object.nil? + date_object = date_object.in_time_zone(timezone) if timezone + date_object.strftime("%m/%d/%Y") + end + + def readable_date date_object + date_object.strftime("%B %d, %Y") + end + + def date_and_time date_object, timezone = nil + date_object = date_object.in_time_zone(timezone) if timezone + date_object.strftime("%m/%d/%Y %I:%M%P (%Z)") + end + + def us_states + [["Alabama", "AL"], ["Alaska", "AK"], ["Arizona", "AZ"], ["Arkansas", "AR"], ["California", "CA"], ["Colorado", "CO"], ["Connecticut", "CT"], ["Delaware", "DE"], ["District of Columbia", "DC"], ["Florida", "FL"], ["Georgia", "GA"], ["Hawaii", "HI"], ["Idaho", "ID"], ["Illinois", "IL"], ["Indiana", "IN"], ["Iowa", "IA"], ["Kansas", "KS"], ["Kentucky", "KY"], ["Louisiana", "LA"], ["Maine", "ME"], ["Maryland", "MD"], ["Massachusetts", "MA"], ["Michigan", "MI"], ["Minnesota", "MN"], ["Mississippi", "MS"], ["Missouri", "MO"], ["Montana", "MT"], ["Nebraska", "NE"], ["Nevada", "NV"], ["New Hampshire", "NH"], ["New Jersey", "NJ"], ["New Mexico", "NM"], ["New York", "NY"], ["North Carolina", "NC"], ["North Dakota", "ND"], ["Ohio", "OH"], ["Oklahoma", "OK"], ["Oregon", "OR"], ["Pennsylvania", "PA"], ["Puerto Rico", "PR"], ["Rhode Island", "RI"], ["South Carolina", "SC"], ["South Dakota", "SD"], ["Tennessee", "TN"], ["Texas", "TX"], ["Utah", "UT"], ["Vermont", "VT"], ["Virginia", "VA"], ["Washington", "WA"], ["West Virginia", "WV"], ["Wisconsin", "WI"], ["Wyoming", "WY"]] + end + + # Prepend 'http://' if it is not present in a given url + # Used for linking to nonprofit-provided website + def add_http url + if url[/^http:\/\//] || url[/^https:\/\//] + url + else + "http://" + url + end + end end diff --git a/app/helpers/card_helper.rb b/app/helpers/card_helper.rb index 8fb509ab8..57bd37932 100644 --- a/app/helpers/card_helper.rb +++ b/app/helpers/card_helper.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CardHelper - - def expiration_years - (0..15).map{|n| (Date.today + n.years).year} - end + def expiration_years + (0..15).map { |n| (Date.today + n.years).year } + end end diff --git a/app/jobs/active_recurring_donations_to_csv_job.rb b/app/jobs/active_recurring_donations_to_csv_job.rb index 45cda1b6f..8db262b70 100644 --- a/app/jobs/active_recurring_donations_to_csv_job.rb +++ b/app/jobs/active_recurring_donations_to_csv_job.rb @@ -2,9 +2,8 @@ class ActiveRecurringDonationsToCsvJob < ExportJob queue_as :default - def perform(opts={}) + def perform(opts = {}) url = ExportRecurringDonations.run_export_for_active_recurring_donations_to_csv(opts[:nonprofit_s3_key], opts[:filename], opts[:export]) export.update(url: url) end - end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index a6dd13698..90269e8be 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -2,4 +2,4 @@ # newer versions of Rails use an ApplicationJob so let's be cool like them class ApplicationJob < ActiveJob::Base queue_as :default -end \ No newline at end of file +end diff --git a/app/jobs/export_job.rb b/app/jobs/export_job.rb index e8dbdec63..695fb2c3d 100644 --- a/app/jobs/export_job.rb +++ b/app/jobs/export_job.rb @@ -12,16 +12,16 @@ class ExportJob < ApplicationJob end after_perform do |job| - job.export.update(status: :completed, ended:Time.current) + job.export.update(status: :completed, ended: Time.current) end - rescue_from 'Exception' do |exception| - self.export.update(status: :failed, ended:Time.current, exception: exception.to_s) + rescue_from "Exception" do |exception| + export.update(status: :failed, ended: Time.current, exception: exception.to_s) raise exception end protected - + # we use these where to get the args in various callbacks def nonprofit arguments.first[:nonprofit] @@ -30,7 +30,7 @@ def nonprofit def user arguments.first[:user] end - + def export arguments.first[:export] end @@ -38,6 +38,4 @@ def export def export=(export) arguments.first[:export] = export end - - end diff --git a/app/jobs/inline_job.rb b/app/jobs/inline_job.rb index 9fb5b2f6f..34652aa66 100644 --- a/app/jobs/inline_job.rb +++ b/app/jobs/inline_job.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # newer versions of Rails use an ApplicationJob so let's be cool like them -class InlineJob< ActiveJob::Base - queue_adapter = :inline -end \ No newline at end of file +class InlineJob < ActiveJob::Base + :inline +end diff --git a/app/jobs/inline_job/modern_object_donation_stripe_charge_job.rb b/app/jobs/inline_job/modern_object_donation_stripe_charge_job.rb index d8065e6dd..9b2a4ab72 100644 --- a/app/jobs/inline_job/modern_object_donation_stripe_charge_job.rb +++ b/app/jobs/inline_job/modern_object_donation_stripe_charge_job.rb @@ -3,7 +3,7 @@ class InlineJob::ModernObjectDonationStripeChargeJob < InlineJob def perform(donation:, legacy_payment:) supporter = Supporter.find(donation.supporter_id) - trx = supporter.transactions.build(amount: legacy_payment.gross_amount, created: legacy_payment['date']) + trx = supporter.transactions.build(amount: legacy_payment.gross_amount, created: legacy_payment["date"]) don = trx.donations.build(amount: legacy_payment.gross_amount, legacy_donation: donation) @@ -13,16 +13,16 @@ def perform(donation:, legacy_payment:) created: legacy_payment.date ) stripe_t = trx.build_subtransaction( - subtransactable: StripeTransaction.new(amount: legacy_payment.gross_amount), - subtransaction_payments:[ + subtransactable: StripeTransaction.new(amount: legacy_payment.gross_amount), + subtransaction_payments: [ stripe_transaction_charge ] - ); + ) trx.save! don.save! stripe_t.save! stripe_t.subtransaction_payments.each(&:publish_created) - #stripe_t.publish_created + # stripe_t.publish_created don.publish_created trx.publish_created end diff --git a/app/jobs/started_recurring_donations_to_csv_job.rb b/app/jobs/started_recurring_donations_to_csv_job.rb index 6cf626f12..1a832e7b6 100644 --- a/app/jobs/started_recurring_donations_to_csv_job.rb +++ b/app/jobs/started_recurring_donations_to_csv_job.rb @@ -2,9 +2,8 @@ class StartedRecurringDonationsToCsvJob < ExportJob queue_as :default - def perform(opts={}) + def perform(opts = {}) url = ExportRecurringDonations.run_export_for_started_recurring_donations_to_csv(opts[:nonprofit_s3_key], opts[:filename], opts[:export]) export.update(url: url) end - end diff --git a/app/legacy_lib/audit.rb b/app/legacy_lib/audit.rb index a7ea242ef..e8fa075e4 100644 --- a/app/legacy_lib/audit.rb +++ b/app/legacy_lib/audit.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Audit - # Given a list of pairs of nonprofit ids and stripe_account_ids (eg [[4341, 'acct_arst'], [3624, 'acct_arst']]) # Find all their available balances on both stripe and CC # Give all the ones that dont match up with the difference @@ -10,7 +9,7 @@ module Audit def self.match_available_balances(nps, date) date ||= Time.current nps.map do |id, stripe_account_id| - cc_bal = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(id, date: date))['net_amount'] + cc_bal = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(id, date: date))["net_amount"] stripe_bal = Stripe::Balance.retrieve(stripe_account: stripe_account_id).available.first.amount [id, stripe_bal - cc_bal] end @@ -31,7 +30,8 @@ def self.payout_check(id) # Return a list of all Stripe transaction objects for an account def self.find_all_transactions(np_id) - logger = ActiveRecord::Base.logger; ActiveRecord::Base.logger = nil + logger = ActiveRecord::Base.logger + ActiveRecord::Base.logger = nil acct = Nonprofit.find(np_id).stripe_account_id starting_after = nil transfers = [] @@ -42,14 +42,14 @@ def self.find_all_transactions(np_id) starting_after = new_transfers.last.id end ActiveRecord::Base.logger = logger - return transfers + transfers end # Given a list of Stripe transaction objects, see if any are missing on CommitChange def self.find_missing_charges(transfers) transfers - .map{|t| [t.source_transaction, t.amount]} - .select{|id, amount| Charge.where(stripe_charge_id: id, amount: amount).empty?} + .map { |t| [t.source_transaction, t.amount] } + .select { |id, amount| Charge.where(stripe_charge_id: id, amount: amount).empty? } end # Audit some basic balances for a nonprofit with those on Stripe @@ -58,52 +58,50 @@ def self.audit_balances(id) puts "Stripe Dashboard: https://dashboard.stripe.com/#{np.stripe_account_id}" puts "CC Payments: https://commitchange.com/nonprofits/#{id}/payments" puts "CC Payouts: https://commitchange.com/nonprofits/#{id}/payouts" - + begin stripe_balances = Stripe::Balance.retrieve(stripe_account: np.stripe_account_id) - available = stripe_balances['available'].first['amount'] - pending = stripe_balances['pending'].first['amount'] - rescue Exception => e + available = stripe_balances["available"].first["amount"] + pending = stripe_balances["pending"].first["amount"] + rescue Exception available = 0 pending = 0 puts "UNRECOGNIZED STRIPE ACCOUNT ID: #{np.stripe_account_id}" end bal = np_balances(id) - data = { + { stripe_net: available + pending, - cc_net: bal['net_amount'], - diff: bal['net_amount'] - (available + pending) + cc_net: bal["net_amount"], + diff: bal["net_amount"] - (available + pending) } - return data end - # Get the total gross, net + # Get the total gross, net # Pretty much duped from QueryPayments def self.np_balances(np_id) - payment_ids_expr = Qx.select('DISTINCT payments.id') + payment_ids_expr = Qx.select("DISTINCT payments.id") .from(:payments) .left_join( - [:charges, 'charges.payment_id=payments.id'], - [:refunds, 'refunds.payment_id=payments.id'], - [:disputes, 'disputes.payment_id=payments.id'] + [:charges, "charges.payment_id=payments.id"], + [:refunds, "refunds.payment_id=payments.id"], + [:disputes, "disputes.payment_id=payments.id"] ) - .where('payments.nonprofit_id=$id', id: np_id) + .where("payments.nonprofit_id=$id", id: np_id) .and_where("refunds.payment_id IS NOT NULL OR charges.payment_id IS NOT NULL OR disputes.payment_id IS NOT NULL") - .and_where(%Q( + .and_where(%( (refunds.payment_id IS NOT NULL AND (refunds.disbursed IS NULL OR refunds.disbursed='f')) OR (charges.status='available' OR charges.status='pending') OR (disputes.status='lost') )) - return Qx.select( - 'coalesce(SUM(payments.gross_amount), 0) AS gross_amount', - 'coalesce(SUM(payments.fee_total), 0) AS fee_total', - 'coalesce(SUM(payments.net_amount), 0) AS net_amount', - 'COUNT(payments.*) AS count' - ) + Qx.select( + "coalesce(SUM(payments.gross_amount), 0) AS gross_amount", + "coalesce(SUM(payments.fee_total), 0) AS fee_total", + "coalesce(SUM(payments.net_amount), 0) AS net_amount", + "COUNT(payments.*) AS count" + ) .from(:payments) .where("payments.id IN ($ids)", ids: payment_ids_expr) .execute .first end - end diff --git a/app/legacy_lib/authentication_error.rb b/app/legacy_lib/authentication_error.rb index 603bff36e..ef9a617bb 100644 --- a/app/legacy_lib/authentication_error.rb +++ b/app/legacy_lib/authentication_error.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class AuthenticationError < RuntimeError -end \ No newline at end of file +end diff --git a/app/legacy_lib/calculate_suggested_amounts.rb b/app/legacy_lib/calculate_suggested_amounts.rb index f91dcc381..69e9f6bd3 100644 --- a/app/legacy_lib/calculate_suggested_amounts.rb +++ b/app/legacy_lib/calculate_suggested_amounts.rb @@ -1,20 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CalculateSuggestedAmounts - require_relative './numeric' # this is loading the local numeric + require_relative "numeric" # this is loading the local numeric MIN = 25 MAX = 100000000 - BRACKETS = [{range: MIN...1000, delta:100}, - {range: 1000...5000, delta: 500}, - {range: 5000...MAX, delta: 2500}] + BRACKETS = [{range: MIN...1000, delta: 100}, + {range: 1000...5000, delta: 500}, + {range: 5000...MAX, delta: 2500}] # Calculates a set of suggested donation amounts based upon our internal special algorithm # This is most useful for suggesting amounts a recurring donor could change to # @return [Array] suggested amounts for your donation # @param [Number] amount the amount in cents to start from def self.calculate(amount) - ParamValidation.new({amount: amount}, amount: {required:true, is_a: Numeric, min: MIN, max:MAX }) + ParamValidation.new({amount: amount}, amount: {required: true, is_a: Numeric, min: MIN, max: MAX}) result = [] step_down_val = step_down_value(amount) @@ -23,29 +23,27 @@ def self.calculate(amount) end higher_amounts = [] - while (higher_amounts.empty? || (higher_amounts.length < 3 && higher_amounts.last() != nil)) + while higher_amounts.empty? || (higher_amounts.length < 3 && !higher_amounts.last.nil?) if higher_amounts.empty? higher_amounts.push(step_up_value(amount)) else higher_amounts.push(step_up_value(higher_amounts.last)) end end - result.concat(higher_amounts.reject {|i| i.nil?}) + result.concat(higher_amounts.reject { |i| i.nil? }) end def self.step_down_value(amount) - initial_bracket = get_bracket_by_amount(amount) - #check_floor_for_delta + # check_floor_for_delta delta_floor = amount.floor_for_delta(initial_bracket[:delta]) - #not on a delta, just send a floor - if (delta_floor != amount) - return delta_floor < MIN ? nil : delta_floor + # not on a delta, just send a floor + if delta_floor != amount + return (delta_floor < MIN) ? nil : delta_floor end - potential_lower_amount = amount - initial_bracket[:delta] # is potential_lower_amount < our MIN? if so, return nil @@ -53,30 +51,27 @@ def self.step_down_value(amount) new_bracket = get_bracket_by_amount(potential_lower_amount) - #if in same bracket, potential_lower_amount is our step_down_value + # if in same bracket, potential_lower_amount is our step_down_value if initial_bracket == new_bracket return potential_lower_amount end - #we're going to step down by our new bracket value then - return amount - new_bracket[:delta] + # we're going to step down by our new bracket value then + amount - new_bracket[:delta] end - def self.step_up_value(amount) - bracket = get_bracket_by_amount(amount) - #check_ceil_for_delta + # check_ceil_for_delta delta_ceil = amount.ceil_for_delta(bracket[:delta]) - #not on a delta, just send a ceil - if (delta_ceil != amount) - return delta_ceil >= MAX ? nil : delta_ceil + # not on a delta, just send a ceil + if delta_ceil != amount + return (delta_ceil >= MAX) ? nil : delta_ceil end - potential_higher_amount = amount + bracket[:delta] # is potential_higher_amount >= our MAX? if so, return nil @@ -85,10 +80,7 @@ def self.step_up_value(amount) potential_higher_amount end - - - def self.get_bracket_by_amount(amount) BRACKETS.select { |i| i[:range].cover?(amount) }.first end -end \ No newline at end of file +end diff --git a/app/legacy_lib/cancel_billing_subscription.rb b/app/legacy_lib/cancel_billing_subscription.rb index 612806c5f..6ab6001d0 100644 --- a/app/legacy_lib/cancel_billing_subscription.rb +++ b/app/legacy_lib/cancel_billing_subscription.rb @@ -1,26 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CancelBillingSubscription - # @param [Nonprofit] nonprofit # @return [BillingSubscription] new billing subscription for the nonprofit - def self.with_stripe(nonprofit) + def self.with_stripe(nonprofit) begin ParamValidation.new({nonprofit: nonprofit}, { - nonprofit: {required: true, is_a: Nonprofit} + nonprofit: {required: true, is_a: Nonprofit} }) rescue ParamValidation::ValidationError => e return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity} end - np_card = nonprofit.active_card - billing_subscription = nonprofit.billing_subscription - return {json:{error: 'We don\'t have a subscription for your non-profit. Please contact support.'}, status: :unprocessable_entity} if np_card.nil? || billing_subscription.nil? # stripe_customer_id on Card object + np_card = nonprofit.active_card + billing_subscription = nonprofit.billing_subscription + return {json: {error: "We don't have a subscription for your non-profit. Please contact support."}, status: :unprocessable_entity} if np_card.nil? || billing_subscription.nil? # stripe_customer_id on Card object # Cancel and delete the subscription on Stripe begin customer = Stripe::Customer.retrieve(np_card.stripe_customer_id) stripe_subscription = customer.subscriptions.retrieve(billing_subscription.stripe_subscription_id) - s = stripe_subscription.delete(at_period_end: false) + stripe_subscription.delete(at_period_end: false) rescue Stripe::StripeError => e return {json: {error: "Oops! There was an error processing your subscription cancellation. Error: #{e}"}, status: :unprocessable_entity} end @@ -28,10 +27,10 @@ def self.with_stripe(nonprofit) billing_plan_id = Settings.default_bp.id billing_subscription.update_attributes({ billing_plan_id: billing_plan_id, - status: 'active' + status: "active" }) - BillingSubscription::clear_cache(nonprofit) - return {json:{}, status: :ok} - end + BillingSubscription.clear_cache(nonprofit) + {json: {}, status: :ok} + end end diff --git a/app/legacy_lib/charge_error.rb b/app/legacy_lib/charge_error.rb index 33ddb2c19..dfed194b1 100644 --- a/app/legacy_lib/charge_error.rb +++ b/app/legacy_lib/charge_error.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ChargeError < RuntimeError -end \ No newline at end of file +end diff --git a/app/legacy_lib/chunked_uploader/s3.rb b/app/legacy_lib/chunked_uploader/s3.rb index 53100e7f9..d3c8b4846 100644 --- a/app/legacy_lib/chunked_uploader/s3.rb +++ b/app/legacy_lib/chunked_uploader/s3.rb @@ -1,22 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ChunkedUploader class S3 - S3_BUCKET_NAME = Settings.aws.bucket_name # Upload a string to s3 using chunks instead of all as one string. This is useful reducing memory usage on huge files # @param [Enumerable] chunk_enum an enumerable of strings. # @param [String] path the path to the object on your S3 bucket # @returns the url to your uploaded file - def self.upload(path,chunk_enum, metadata={}) + def self.upload(path, chunk_enum, metadata = {}) s3 = ::Aws::S3::Resource.new bucket = s3.bucket(S3_BUCKET_NAME) object = bucket.object(path) - content_type = metadata[:content_type] ? metadata[:content_type] : nil - content_disposition = metadata[:content_disposition] ? metadata[:content_disposition] : nil + content_type = metadata[:content_type] || nil + content_disposition = metadata[:content_disposition] || nil - object.upload_stream(temp_file:true, acl: 'public-read', content_type: content_type, content_disposition: content_disposition) do |write_stream| - chunk_enum.each do |chunk| + object.upload_stream(temp_file: true, acl: "public-read", content_type: content_type, content_disposition: content_disposition) do |write_stream| + chunk_enum.each do |chunk| write_stream << chunk end end @@ -24,4 +23,4 @@ def self.upload(path,chunk_enum, metadata={}) object.public_url.to_s end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/construct_nonprofit.rb b/app/legacy_lib/construct_nonprofit.rb index c482adba1..83b1d230e 100644 --- a/app/legacy_lib/construct_nonprofit.rb +++ b/app/legacy_lib/construct_nonprofit.rb @@ -1,15 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ConstructNonprofit - - def self.construct(user, h) - h[:published] = true - h[:statement] = h[:name][0..16] - h.except!(:website) if h[:website].blank? - stripe_acct = CreateStripeAccount.for_nonprofit(user, h) - h[:stripe_account_id] = stripe_acct.id - return h - end - + def self.construct(user, h) + h[:published] = true + h[:statement] = h[:name][0..16] + h.except!(:website) if h[:website].blank? + stripe_acct = CreateStripeAccount.for_nonprofit(user, h) + h[:stripe_account_id] = stripe_acct.id + h + end end - diff --git a/app/legacy_lib/controllers/campaign_helper.rb b/app/legacy_lib/controllers/campaign_helper.rb index d7a568a0f..5e4aaff81 100644 --- a/app/legacy_lib/controllers/campaign_helper.rb +++ b/app/legacy_lib/controllers/campaign_helper.rb @@ -1,23 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Controllers::CampaignHelper - include Controllers::NonprofitHelper + include Controllers::NonprofitHelper -private + private - def current_campaign - @campaign ||= FetchCampaign.with_params params, current_nonprofit - raise ActionController::RoutingError.new "Campaign not found" if @campaign.nil? - return @campaign - end + def current_campaign + @campaign ||= FetchCampaign.with_params params, current_nonprofit + raise ActionController::RoutingError.new "Campaign not found" if @campaign.nil? + @campaign + end - def current_campaign_editor? - !params[:preview] && (current_nonprofit_user? || current_role?(:campaign_editor, current_campaign.id) || current_role?(:super_admin)) - end - - def authenticate_campaign_editor! - unless current_campaign_editor? - block_with_sign_in 'You need to be a campaign editor to do that.' - end - end + def current_campaign_editor? + !params[:preview] && (current_nonprofit_user? || current_role?(:campaign_editor, current_campaign.id) || current_role?(:super_admin)) + end + def authenticate_campaign_editor! + unless current_campaign_editor? + block_with_sign_in "You need to be a campaign editor to do that." + end + end end diff --git a/app/legacy_lib/controllers/event_helper.rb b/app/legacy_lib/controllers/event_helper.rb index a58c778f4..6872ecc0c 100644 --- a/app/legacy_lib/controllers/event_helper.rb +++ b/app/legacy_lib/controllers/event_helper.rb @@ -1,27 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Controllers::EventHelper - include Controllers::NonprofitHelper + include Controllers::NonprofitHelper -private + private - def current_event_admin? - current_nonprofit_admin? - end + def current_event_admin? + current_nonprofit_admin? + end - def current_event_editor? - !params[:preview] && (current_nonprofit_user? || current_role?(:event_editor, current_event.id) || current_role?(:super_admin)) - end + def current_event_editor? + !params[:preview] && (current_nonprofit_user? || current_role?(:event_editor, current_event.id) || current_role?(:super_admin)) + end - def authenticate_event_editor! - unless current_event_editor? - block_with_sign_in 'You need to be the event organizer or a nonprofit administrator before doing that.' - end - end - - def current_event - @event ||= FetchEvent.with_params params, current_nonprofit - raise ActionController::RoutingError.new "Event not found" if @event.nil? - return @event - end + def authenticate_event_editor! + unless current_event_editor? + block_with_sign_in "You need to be the event organizer or a nonprofit administrator before doing that." + end + end + def current_event + @event ||= FetchEvent.with_params params, current_nonprofit + raise ActionController::RoutingError.new "Event not found" if @event.nil? + @event + end end diff --git a/app/legacy_lib/controllers/nonprofit_helper.rb b/app/legacy_lib/controllers/nonprofit_helper.rb index 7aae64012..676ea061d 100644 --- a/app/legacy_lib/controllers/nonprofit_helper.rb +++ b/app/legacy_lib/controllers/nonprofit_helper.rb @@ -1,63 +1,60 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Controllers::NonprofitHelper + private -private + def authenticate_nonprofit_user! + unless current_nonprofit_user? + block_with_sign_in "Please sign in" + end + end - def authenticate_nonprofit_user! - unless current_nonprofit_user? - block_with_sign_in 'Please sign in' - end - end + def authenticate_nonprofit_admin! + unless current_nonprofit_admin? + block_with_sign_in "Please sign in" + end + end - def authenticate_nonprofit_admin! - unless current_nonprofit_admin? - block_with_sign_in 'Please sign in' - end - end - - def current_nonprofit_user? + def current_nonprofit_user? return false if params[:preview] - return false unless current_nonprofit_without_exception - @current_user_role ||= current_role?([:nonprofit_admin, :nonprofit_associate], current_nonprofit_without_exception.id) || current_role?(:super_admin) - end - - def current_nonprofit_admin? - return false if !current_user || current_user.roles.empty? - @current_admin_role ||= current_role?(:nonprofit_admin, current_nonprofit.id) || current_role?(:super_admin) - end - - def current_nonprofit - @nonprofit = current_nonprofit_without_exception - raise ActionController::RoutingError.new "Nonprofit not found" if @nonprofit.nil? - return @nonprofit - end - - def current_nonprofit_without_exception - key = "current_nonprofit_#{current_user_id}_params_#{[params[:state_code], params[:city], params[:name], params[:nonprofit_id], params[:id]].join("_")}" + return false unless current_nonprofit_without_exception + @current_user_role ||= current_role?([:nonprofit_admin, :nonprofit_associate], current_nonprofit_without_exception.id) || current_role?(:super_admin) + end + + def current_nonprofit_admin? + return false if !current_user || current_user.roles.empty? + @current_admin_role ||= current_role?(:nonprofit_admin, current_nonprofit.id) || current_role?(:super_admin) + end + + def current_nonprofit + @nonprofit = current_nonprofit_without_exception + raise ActionController::RoutingError.new "Nonprofit not found" if @nonprofit.nil? + @nonprofit + end + + def current_nonprofit_without_exception FetchNonprofit.with_params params, administered_nonprofit - end - - def donation_stub - return current_nonprofit_without_exception.donations.last unless current_nonprofit_without_exception.donations.empty? - OpenStruct.new( - amount: 2000, - created_at: Time.zone.now, - nonprofit: current_nonprofit_without_exception, - campaign: nil, - designation: "Donor's designation here", - dedication: "Donor's dedication here", - id: 1 - ) - end - - def reject_for_deactivated_nonprofits - if current_nonprofit&.nonprofit_deactivation&.deactivated - render plain: '', status: :unauthorized - end - end - - def must_block?(nonprofit=nil) - (nonprofit || current_nonprofit)&.miscellaneous_np_info&.temp_block - end - + end + + def donation_stub + return current_nonprofit_without_exception.donations.last unless current_nonprofit_without_exception.donations.empty? + OpenStruct.new( + amount: 2000, + created_at: Time.zone.now, + nonprofit: current_nonprofit_without_exception, + campaign: nil, + designation: "Donor's designation here", + dedication: "Donor's dedication here", + id: 1 + ) + end + + def reject_for_deactivated_nonprofits + if current_nonprofit&.nonprofit_deactivation&.deactivated + render plain: "", status: :unauthorized + end + end + + def must_block?(nonprofit = nil) + (nonprofit || current_nonprofit)&.miscellaneous_np_info&.temp_block + end end diff --git a/app/legacy_lib/copy_naming_algorithm.rb b/app/legacy_lib/copy_naming_algorithm.rb index 729c7eba0..4d83f29b3 100644 --- a/app/legacy_lib/copy_naming_algorithm.rb +++ b/app/legacy_lib/copy_naming_algorithm.rb @@ -30,36 +30,34 @@ def get_name_for_entity(name_entity) def create_copy_name(name_to_copy) # remove copy addition and number - base_name = name_to_copy.gsub(/#{Regexp.quote(self.copy_addition)}(#{Regexp.quote(separator_before_copy_number)}\d+)?\z/,'') - name_entities_to_check_against = get_already_used_name_entities(base_name).collect{|entity| self.get_name_for_entity(entity)}.to_a - (0..max_copies-1).each {|copy_num| + base_name = name_to_copy.gsub(/#{Regexp.quote(copy_addition)}(#{Regexp.quote(separator_before_copy_number)}\d+)?\z/, "") + name_entities_to_check_against = get_already_used_name_entities(base_name).collect { |entity| get_name_for_entity(entity) }.to_a + (0..max_copies - 1).each { |copy_num| name_to_test = generate_name(base_name, copy_num) - if (name_entities_to_check_against.none? {|entity_name| entity_name == name_to_test}) + if name_entities_to_check_against.none? { |entity_name| entity_name == name_to_test } return name_to_test end } - raise UnableToCreateNameCopyError.new("It's not possible to generate a UNIQUE name using name_to_copy: #{name_to_copy} copy_addition: #{self.copy_addition} separator_before_copy_number: #{self.separator_before_copy_number} max_copy_num: #{self.max_copies} max_length: #{self.max_length}") + raise UnableToCreateNameCopyError.new("It's not possible to generate a UNIQUE name using name_to_copy: #{name_to_copy} copy_addition: #{copy_addition} separator_before_copy_number: #{separator_before_copy_number} max_copy_num: #{max_copies} max_length: #{max_length}") end def generate_name(name_to_copy, copy_num) - what_to_add = self.copy_addition + self.separator_before_copy_number + generate_copy_number(copy_num) + what_to_add = copy_addition + separator_before_copy_number + generate_copy_number(copy_num) # is what_to_add longer than max length? If so, it's not possible to create a copy - if (what_to_add.length > self.max_length) - raise UnableToCreateNameCopyError.new("It's not possible to generate a name using name_to_copy: #{name_to_copy} copy_addition: #{self.copy_addition} separator_before_copy_number: #{self.separator_before_copy_number} copy_num: #{copy_num} max_length: #{self.max_length}") + if what_to_add.length > max_length + raise UnableToCreateNameCopyError.new("It's not possible to generate a name using name_to_copy: #{name_to_copy} copy_addition: #{copy_addition} separator_before_copy_number: #{separator_before_copy_number} copy_num: #{copy_num} max_length: #{max_length}") end - max_length_for_name_to_copy = self.max_length - what_to_add.length - name_to_copy[0..max_length_for_name_to_copy-1] + what_to_add + max_length_for_name_to_copy = max_length - what_to_add.length + name_to_copy[0..max_length_for_name_to_copy - 1] + what_to_add end def generate_copy_number(unprefixed_copy_number) - number_of_digits = Math.log10(self.max_copies).floor + 1 + number_of_digits = Math.log10(max_copies).floor + 1 "%0#{number_of_digits}d" % unprefixed_copy_number end - end class UnableToCreateNameCopyError < ArgumentError - -end \ No newline at end of file +end diff --git a/app/legacy_lib/create_campaign.rb b/app/legacy_lib/create_campaign.rb index b9b7dd036..eb004eedc 100644 --- a/app/legacy_lib/create_campaign.rb +++ b/app/legacy_lib/create_campaign.rb @@ -1,5 +1,4 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CreateCampaign CAMPAIGN_NAME_LENGTH_LIMIT = 60 - -end \ No newline at end of file +end diff --git a/app/legacy_lib/create_campaign_gift.rb b/app/legacy_lib/create_campaign_gift.rb index 13a359e6b..89641710b 100644 --- a/app/legacy_lib/create_campaign_gift.rb +++ b/app/legacy_lib/create_campaign_gift.rb @@ -1,82 +1,81 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CreateCampaignGift - # @param [Hash] params - # * campaign_gift_option_id - # * donation_id - def self.create(params) - ParamValidation.new(params, { - :campaign_gift_option_id => { - :required => true, - :is_integer => true - }, - :donation_id => { - :required => true, - :is_integer => true - } - }) + # @param [Hash] params + # * campaign_gift_option_id + # * donation_id + def self.create(params) + ParamValidation.new(params, { + campaign_gift_option_id: { + required: true, + is_integer: true + }, + donation_id: { + required: true, + is_integer: true + } + }) - donation = Donation.includes(:nonprofit).includes(:supporter).includes(:recurring_donation).includes(:campaign_gifts).where('id = ?', params[:donation_id]).first - unless donation - raise ParamValidation::ValidationError.new("#{params[:donation_id]} is not a valid donation id.", {:key => :donation_id}) - end + donation = Donation.includes(:nonprofit).includes(:supporter).includes(:recurring_donation).includes(:campaign_gifts).where("id = ?", params[:donation_id]).first + unless donation + raise ParamValidation::ValidationError.new("#{params[:donation_id]} is not a valid donation id.", {key: :donation_id}) + end - campaign_gift_option = CampaignGiftOption.includes(:campaign).where('id = ?', params[:campaign_gift_option_id]).first - unless campaign_gift_option - raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} is not a valid campaign gift option", {:key => :campaign_gift_option_id}) - end + campaign_gift_option = CampaignGiftOption.includes(:campaign).where("id = ?", params[:campaign_gift_option_id]).first + unless campaign_gift_option + raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} is not a valid campaign gift option", {key: :campaign_gift_option_id}) + end - #does donation already have a campaign_gift - if (donation.campaign_gifts.any?) - raise ParamValidation::ValidationError.new("#{params[:donation_id]} already has at least one associated campaign gift", :key => :donation_id) - end + # does donation already have a campaign_gift + if donation.campaign_gifts.any? + raise ParamValidation::ValidationError.new("#{params[:donation_id]} already has at least one associated campaign gift", key: :donation_id) + end - if (donation.campaign != campaign_gift_option.campaign) - raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} is not for the same campaign as donation #{params[:donation_id]}", {:key => :campaign_gift_option_id}) - end + if donation.campaign != campaign_gift_option.campaign + raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} is not for the same campaign as donation #{params[:donation_id]}", {key: :campaign_gift_option_id}) + end - billing_plan = donation.nonprofit.billing_plan + donation.nonprofit.billing_plan - if ((donation.recurring_donation != nil) && (campaign_gift_option.amount_recurring != nil && campaign_gift_option.amount_recurring > 0)) - # it's a recurring_donation. Is it enough? for the gift level? - unless donation.recurring_donation.amount >= campaign_gift_option.amount_recurring # || (donation.recurring_donation.amount - CalculateFees.for_single_amount(donation.recurring_donation.amount, billing_plan.percentage_fee) == campaign_gift_option.amount_recurring) - AdminMailer.delay.notify_failed_gift(donation, donation.payments.first, campaign_gift_option) - raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} gift options requires a recurring donation of #{campaign_gift_option.amount_recurring} for donation #{donation.id}", {:key => :campaign_gift_option_id}) - end - else - unless donation.amount >= (campaign_gift_option.amount_one_time) # || (donation.amount - CalculateFees.for_single_amount(donation.amount, billing_plan.percentage_fee) == campaign_gift_option.amount_one_time) - AdminMailer.delay.notify_failed_gift(donation,donation.payments.first, campaign_gift_option) - raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} gift options requires a donation of #{campaign_gift_option.amount_one_time} for donation #{donation.id}", {:key => :campaign_gift_option_id}) - end - end + if !donation.recurring_donation.nil? && !campaign_gift_option.amount_recurring.nil? && campaign_gift_option.amount_recurring > 0 + # it's a recurring_donation. Is it enough? for the gift level? + unless donation.recurring_donation.amount >= campaign_gift_option.amount_recurring # || (donation.recurring_donation.amount - CalculateFees.for_single_amount(donation.recurring_donation.amount, billing_plan.percentage_fee) == campaign_gift_option.amount_recurring) + AdminMailer.delay.notify_failed_gift(donation, donation.payments.first, campaign_gift_option) + raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} gift options requires a recurring donation of #{campaign_gift_option.amount_recurring} for donation #{donation.id}", {key: :campaign_gift_option_id}) + end + else + unless donation.amount >= campaign_gift_option.amount_one_time # || (donation.amount - CalculateFees.for_single_amount(donation.amount, billing_plan.percentage_fee) == campaign_gift_option.amount_one_time) + AdminMailer.delay.notify_failed_gift(donation, donation.payments.first, campaign_gift_option) + raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} gift options requires a donation of #{campaign_gift_option.amount_one_time} for donation #{donation.id}", {key: :campaign_gift_option_id}) + end + end - successful_gift = Qx.transaction do - # are any gifts available? - if campaign_gift_option.quantity.nil? || campaign_gift_option.quantity.zero?|| campaign_gift_option.total_gifts < campaign_gift_option.quantity - CampaignGift.create!(params) - end - end + successful_gift = Qx.transaction do + # are any gifts available? + if campaign_gift_option.quantity.nil? || campaign_gift_option.quantity.zero? || campaign_gift_option.total_gifts < campaign_gift_option.quantity + CampaignGift.create!(params) + end + end - unless successful_gift - AdminMailer.delay.notify_failed_gift(donation,donation.payments.first, campaign_gift_option) - raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} has no more inventory", {:key => :campaign_gift_option_id}) - end + unless successful_gift + AdminMailer.delay.notify_failed_gift(donation, donation.payments.first, campaign_gift_option) + raise ParamValidation::ValidationError.new("#{params[:campaign_gift_option_id]} has no more inventory", {key: :campaign_gift_option_id}) + end - successful_gift - end - - def self.validate_campaign_gift(cg) - donation = cg.donation - campaign_gift_option = cg.campaign_gift_option - if ((donation.recurring_donation != nil) && (campaign_gift_option.amount_recurring != nil && campaign_gift_option.amount_recurring > 0)) - # it's a recurring_donation. Is it enough? for the gift level? - unless donation.recurring_donation.amount == (campaign_gift_option.amount_recurring) - raise ParamValidation::ValidationError.new("#{campaign_gift_option.id} gift options requires a recurring donation of at least #{campaign_gift_option.amount_recurring}", {:key => :campaign_gift_option_id}) - end - else - unless donation.amount == (campaign_gift_option.amount_one_time) - raise ParamValidation::ValidationError.new("#{campaign_gift_option.id} gift options requires a donation of at least #{campaign_gift_option.amount_one_time}", {:key => :campaign_gift_option_id}) - end - end - end + successful_gift + end + def self.validate_campaign_gift(cg) + donation = cg.donation + campaign_gift_option = cg.campaign_gift_option + if !donation.recurring_donation.nil? && !campaign_gift_option.amount_recurring.nil? && campaign_gift_option.amount_recurring > 0 + # it's a recurring_donation. Is it enough? for the gift level? + unless donation.recurring_donation.amount == campaign_gift_option.amount_recurring + raise ParamValidation::ValidationError.new("#{campaign_gift_option.id} gift options requires a recurring donation of at least #{campaign_gift_option.amount_recurring}", {key: :campaign_gift_option_id}) + end + else + unless donation.amount == campaign_gift_option.amount_one_time + raise ParamValidation::ValidationError.new("#{campaign_gift_option.id} gift options requires a donation of at least #{campaign_gift_option.amount_one_time}", {key: :campaign_gift_option_id}) + end + end + end end diff --git a/app/legacy_lib/create_campaign_gift_option.rb b/app/legacy_lib/create_campaign_gift_option.rb index 98ca146bd..2f7cc2556 100644 --- a/app/legacy_lib/create_campaign_gift_option.rb +++ b/app/legacy_lib/create_campaign_gift_option.rb @@ -1,10 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CreateCampaignGiftOption - - def self.create campaign, params - gift_option = campaign.campaign_gift_options.build params - gift_option.save - return gift_option - end - + def self.create campaign, params + gift_option = campaign.campaign_gift_options.build params + gift_option.save + gift_option + end end diff --git a/app/legacy_lib/create_custom_field_join.rb b/app/legacy_lib/create_custom_field_join.rb index 55ebc38ce..fcbc9b24c 100644 --- a/app/legacy_lib/create_custom_field_join.rb +++ b/app/legacy_lib/create_custom_field_join.rb @@ -1,39 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CreateCustomFieldJoin + def self.create(supporter, profile_id, params) + supporter.custom_field_joins.create(params) + end - def self.create(supporter, profile_id, params) - custom_field = supporter.custom_field_joins.create(params) - return custom_field - end + # In the future, this should create an activity feed entry - # In the future, this should create an activity feed entry - - # @param [Array] custom_fields Hash with following keys: + # @param [Array] custom_fields Hash with following keys: # * custom_field_master_id [Integer] for the key corresponding to custom_field_master_id - # * value [Object] the expected value of the field. If this key is an empty string, we remove the custom_field - - def self.modify(np, user, supporter_ids, custom_fields) - return if supporter_ids.nil? || supporter_ids.empty? - return if custom_fields.nil? || custom_fields.empty? - supporter_ids.each do |sid| - supporter = np.supporters.find(sid) - custom_fields.each do |custom_field| - existing = supporter.custom_field_joins.find_by_custom_field_master_id(custom_field[:custom_field_master_id]) - if existing - existing.update_attributes({ - custom_field_master_id: custom_field[:custom_field_master_id], - value: custom_field[:value] - }) - else - self.create(supporter, user.profile.id, { - custom_field_master_id: custom_field[:custom_field_master_id], - value: custom_field[:value] - }) - end - end - end - return np - end + # * value [Object] the expected value of the field. If this key is an empty string, we remove the custom_field + def self.modify(np, user, supporter_ids, custom_fields) + return if supporter_ids.nil? || supporter_ids.empty? + return if custom_fields.nil? || custom_fields.empty? + supporter_ids.each do |sid| + supporter = np.supporters.find(sid) + custom_fields.each do |custom_field| + existing = supporter.custom_field_joins.find_by_custom_field_master_id(custom_field[:custom_field_master_id]) + if existing + existing.update_attributes({ + custom_field_master_id: custom_field[:custom_field_master_id], + value: custom_field[:value] + }) + else + create(supporter, user.profile.id, { + custom_field_master_id: custom_field[:custom_field_master_id], + value: custom_field[:value] + }) + end + end + end + np + end end - diff --git a/app/legacy_lib/create_custom_field_master.rb b/app/legacy_lib/create_custom_field_master.rb index decc7ce63..098015097 100644 --- a/app/legacy_lib/create_custom_field_master.rb +++ b/app/legacy_lib/create_custom_field_master.rb @@ -1,8 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CreateCustomFieldMaster - - def self.create(nonprofit, params) - custom_field_master = nonprofit.custom_field_masters.create(params) - return custom_field_master - end + def self.create(nonprofit, params) + nonprofit.custom_field_masters.create(params) + end end diff --git a/app/legacy_lib/create_peer_to_peer_campaign.rb b/app/legacy_lib/create_peer_to_peer_campaign.rb index af7b024b1..c4df427a5 100644 --- a/app/legacy_lib/create_peer_to_peer_campaign.rb +++ b/app/legacy_lib/create_peer_to_peer_campaign.rb @@ -2,13 +2,12 @@ module CreatePeerToPeerCampaign def self.create(campaign_params, profile_id) begin - parent_campaign = Campaign.find(campaign_params[:parent_campaign_id]) - + parent_campaign = Campaign.find(campaign_params[:parent_campaign_id]) rescue ActiveRecord::RecordNotFound - return { errors: { parent_campaign_id: 'not found' } }.as_json + return {errors: {parent_campaign_id: "not found"}}.as_json end - p2p_params = campaign_params.except(:nonprofit_id, :summary,:goal_amount, :widget_description_id).to_deprecated_h + p2p_params = campaign_params.except(:nonprofit_id, :summary, :goal_amount, :widget_description_id).to_deprecated_h p2p_params.merge!(parent_campaign.child_params) profile = Profile.find(profile_id) @@ -16,7 +15,7 @@ def self.create(campaign_params, profile_id) algo = SlugP2pCampaignNamingAlgorithm.new(p2p_params[:nonprofit_id]) p2p_params[:slug] = algo.create_copy_name(base_slug) - #child campaigns are always in dollars, not supporters + # child campaigns are always in dollars, not supporters p2p_params[:goal_is_in_supporters] = false campaign = Campaign.create(p2p_params) @@ -25,11 +24,23 @@ def self.create(campaign_params, profile_id) campaign.profile = profile campaign.save - campaign.update_attribute(:main_image, parent_campaign.main_image) unless !parent_campaign.main_image rescue Aws::S3::Errors::NoSuchKey - campaign.update_attribute(:background_image, parent_campaign.background_image) unless !parent_campaign.background_image rescue Aws::S3::Errors::NoSuchKey - campaign.update_attribute(:banner_image, parent_campaign.banner_image) unless !parent_campaign.banner_image rescue Aws::S3::Errors::NoSuchKey + begin + campaign.update_attribute(:main_image, parent_campaign.main_image) unless !parent_campaign.main_image + rescue + Aws::S3::Errors::NoSuchKey + end + begin + campaign.update_attribute(:background_image, parent_campaign.background_image) unless !parent_campaign.background_image + rescue + Aws::S3::Errors::NoSuchKey + end + begin + campaign.update_attribute(:banner_image, parent_campaign.banner_image) unless !parent_campaign.banner_image + rescue + Aws::S3::Errors::NoSuchKey + end - return { errors: campaign.errors.messages }.as_json unless campaign.errors.empty? + return {errors: campaign.errors.messages}.as_json unless campaign.errors.empty? campaign.as_json end diff --git a/app/legacy_lib/create_stripe_account.rb b/app/legacy_lib/create_stripe_account.rb index 1d1a9412d..dab528a5b 100644 --- a/app/legacy_lib/create_stripe_account.rb +++ b/app/legacy_lib/create_stripe_account.rb @@ -1,37 +1,36 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'format/name' -require 'get_data' -require 'stripe' +require "format/name" +require "get_data" +require "stripe" module CreateStripeAccount - - def self.for_nonprofit(user, params) - fst_name, lst_name = Format::Name.split_full(GetData.chain(user, :profile, :name)) - return Stripe::Account.create({ - managed: true, - email: params[:email], - business_name: params[:name], - business_url: params[:website], - legal_entity: { - type: 'company', - address: { - line1: params[:address], - city: params[:city], - state: params[:state_code], - postal_code: params[:zip_code], - country: 'US' - }, - business_name: params[:name], - business_tax_id: params[:ein], - first_name: fst_name, - last_name: lst_name - }, - product_description: 'Nonprofit donations', - tos_acceptance: { - date: Time.current.to_i, - ip: user.current_sign_in_ip - }, - transfer_schedule: { interval: 'manual' } - }) - end + def self.for_nonprofit(user, params) + fst_name, lst_name = Format::Name.split_full(GetData.chain(user, :profile, :name)) + Stripe::Account.create({ + managed: true, + email: params[:email], + business_name: params[:name], + business_url: params[:website], + legal_entity: { + type: "company", + address: { + line1: params[:address], + city: params[:city], + state: params[:state_code], + postal_code: params[:zip_code], + country: "US" + }, + business_name: params[:name], + business_tax_id: params[:ein], + first_name: fst_name, + last_name: lst_name + }, + product_description: "Nonprofit donations", + tos_acceptance: { + date: Time.current.to_i, + ip: user.current_sign_in_ip + }, + transfer_schedule: {interval: "manual"} + }) + end end diff --git a/app/legacy_lib/create_tag_master.rb b/app/legacy_lib/create_tag_master.rb index 7c8fc1396..68742216c 100644 --- a/app/legacy_lib/create_tag_master.rb +++ b/app/legacy_lib/create_tag_master.rb @@ -1,9 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module CreateTagMaster - - def self.create(nonprofit, params) - tag_master = nonprofit.tag_masters.create(params) - return tag_master - end + def self.create(nonprofit, params) + nonprofit.tag_masters.create(params) + end end - diff --git a/app/legacy_lib/cypher.rb b/app/legacy_lib/cypher.rb index 3f95b517e..c8c8e87ff 100644 --- a/app/legacy_lib/cypher.rb +++ b/app/legacy_lib/cypher.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'openssl' +require "openssl" # This module is useful for encrypting columns into the database # For the encrypted column, store it as "text" types @@ -8,31 +8,29 @@ # .iv, .auth_tag both are stored with the encrypted data module Cypher - def self.encrypt(data) cipher = create_cipher cipher.encrypt - cipher.key = Base64.decode64(ENV['CYPHER_KEY']) + cipher.key = Base64.decode64(ENV["CYPHER_KEY"]) iv = cipher.random_iv encrypted = cipher.update(data) + cipher.final - return {iv: Base64.encode64(iv), key: Base64.encode64(encrypted)} + {iv: Base64.encode64(iv), key: Base64.encode64(encrypted)} end # hash must have properties for :iv and :key def self.decrypt(hash) - iv, encrypted = [Base64.decode64(hash['iv']), Base64.decode64(hash['key'])] + iv, encrypted = [Base64.decode64(hash["iv"]), Base64.decode64(hash["key"])] decipher = create_cipher decipher.decrypt - decipher.key = Base64.decode64(ENV['CYPHER_KEY']) + decipher.key = Base64.decode64(ENV["CYPHER_KEY"]) decipher.iv = iv - return decipher.update(encrypted) + decipher.final + decipher.update(encrypted) + decipher.final end -private + private def self.create_cipher - OpenSSL::Cipher::AES256.new(:CBC) + OpenSSL::Cipher.new("aes-256-cbc") end - end diff --git a/app/legacy_lib/delayed_job_helper.rb b/app/legacy_lib/delayed_job_helper.rb index 7189a29e5..c54a86292 100644 --- a/app/legacy_lib/delayed_job_helper.rb +++ b/app/legacy_lib/delayed_job_helper.rb @@ -1,17 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' -require 'delayed_job' +require "qx" +require "delayed_job" module DelayedJobHelper - - # Create a serialized delayed job handler for use in inserting new delayed jobs with raw sql - # Be sure to wrap the handler in double quotes when inserting, not single - def self.create_handler(obj, method_name, args) - Delayed::PerformableMethod.new(obj, method_name, args).to_yaml.to_s - end + # Create a serialized delayed job handler for use in inserting new delayed jobs with raw sql + # Be sure to wrap the handler in double quotes when inserting, not single + def self.create_handler(obj, method_name, args) + Delayed::PerformableMethod.new(obj, method_name, args).to_yaml.to_s + end # Manually enqueue a job - def self.enqueue_job(obj, method_name, args, options={}) + def self.enqueue_job(obj, method_name, args, options = {}) handler = Delayed::PerformableMethod.new(obj, method_name, args).to_yaml.to_s Qx.insert_into(:delayed_jobs) .values({ @@ -22,6 +21,6 @@ def self.enqueue_job(obj, method_name, args, options={}) handler: handler, run_at: options[:run_at] || Time.current, queue: options[:queue] - }).returning('*').execute + }).returning("*").execute end end diff --git a/app/legacy_lib/delete_campaign.rb b/app/legacy_lib/delete_campaign.rb index 5de074100..79d366786 100644 --- a/app/legacy_lib/delete_campaign.rb +++ b/app/legacy_lib/delete_campaign.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module DeleteCampaign - - # This is NOT recommended. We only do this in special cases as campaigns - # should never be totally deleted, only "hidden" - def self.delete(campaign) - if safe_to_delete?(campaign) - campaign.destroy - end + # This is NOT recommended. We only do this in special cases as campaigns + # should never be totally deleted, only "hidden" + def self.delete(campaign) + if safe_to_delete?(campaign) + campaign.destroy end + end - def self.safe_to_delete?(campaign) - campaign.payments.none? && campaign.donations.none? && campaign.activities.none? && (campaign.child_campaign? || campaign.children_campaigns.none?) - end -end \ No newline at end of file + def self.safe_to_delete?(campaign) + campaign.payments.none? && campaign.donations.none? && campaign.activities.none? && (campaign.child_campaign? || campaign.children_campaigns.none?) + end +end diff --git a/app/legacy_lib/delete_campaign_gift_option.rb b/app/legacy_lib/delete_campaign_gift_option.rb index d049619ef..af5580811 100644 --- a/app/legacy_lib/delete_campaign_gift_option.rb +++ b/app/legacy_lib/delete_campaign_gift_option.rb @@ -1,27 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module DeleteCampaignGiftOption def self.delete(campaign, campaign_gift_option_id) - ParamValidation.new({:campaign => campaign, - :campaign_gift_option_id => campaign_gift_option_id}, - { - :campaign => { - :required => true, - :is_a => Campaign - }, - :campaign_gift_option_id => { - :required => true, - :is_integer => true - } - } - ) + ParamValidation.new({campaign: campaign, + campaign_gift_option_id: campaign_gift_option_id}, + { + campaign: { + required: true, + is_a: Campaign + }, + campaign_gift_option_id: { + required: true, + is_integer: true + } + }) Qx.transaction do - cgo = campaign.campaign_gift_options.where('id = ? ', campaign_gift_option_id).first + cgo = campaign.campaign_gift_options.where("id = ? ", campaign_gift_option_id).first unless cgo - raise ParamValidation::ValidationError.new("#{campaign_gift_option_id} is not a valid gift option for campaign #{campaign.id}", {:key => :campaign_gift_option_id}) + raise ParamValidation::ValidationError.new("#{campaign_gift_option_id} is not a valid gift option for campaign #{campaign.id}", {key: :campaign_gift_option_id}) end - if (cgo.campaign_gifts.any?) - raise ParamValidation::ValidationError.new("#{campaign_gift_option_id} already has campaign gifts. It can't be deleted for safety reasons.", {:key => :campaign_gift_option_id}) + if cgo.campaign_gifts.any? + raise ParamValidation::ValidationError.new("#{campaign_gift_option_id} already has campaign gifts. It can't be deleted for safety reasons.", {key: :campaign_gift_option_id}) end cgo.destroy @@ -29,4 +28,4 @@ def self.delete(campaign, campaign_gift_option_id) cgo end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/delete_custom_field_joins.rb b/app/legacy_lib/delete_custom_field_joins.rb index ac3e8080b..b778cba52 100644 --- a/app/legacy_lib/delete_custom_field_joins.rb +++ b/app/legacy_lib/delete_custom_field_joins.rb @@ -1,24 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module DeleteCustomFieldJoins - @columns = ['id', 'custom_field_master_id', 'supporter_id', 'value', 'created_at', 'updated_at', 'metadata'] + @columns = ["id", "custom_field_master_id", "supporter_id", "value", "created_at", "updated_at", "metadata"] def self.find_multiple_custom_field_joins - bad_results = Qx.select("CONCAT(custom_field_joins.supporter_id, '_', custom_field_joins.custom_field_master_id) AS our_concat, COUNT(id) AS our_count"). - from(:custom_field_joins). - group_by("our_concat"). - having('COUNT(id) > 1').parse - - - custom_field_joins_from_qx = CustomFieldJoin. - where("CONCAT(custom_field_joins.supporter_id, '_', custom_field_joins.custom_field_master_id) IN (SELECT our_concat FROM (#{bad_results}) AS ignore)"). - select('id, custom_field_master_id, supporter_id, created_at, updated_at') - grouped_custom_field_joins = custom_field_joins_from_qx.group_by{|tj| "#{tj.supporter_id}_#{tj.custom_field_master_id}"} + bad_results = Qx.select("CONCAT(custom_field_joins.supporter_id, '_', custom_field_joins.custom_field_master_id) AS our_concat, COUNT(id) AS our_count") + .from(:custom_field_joins) + .group_by("our_concat") + .having("COUNT(id) > 1").parse + custom_field_joins_from_qx = CustomFieldJoin + .where("CONCAT(custom_field_joins.supporter_id, '_', custom_field_joins.custom_field_master_id) IN (SELECT our_concat FROM (#{bad_results}) AS ignore)") + .select("id, custom_field_master_id, supporter_id, created_at, updated_at") + grouped_custom_field_joins = custom_field_joins_from_qx.group_by { |tj| "#{tj.supporter_id}_#{tj.custom_field_master_id}" } ids_to_delete = [] grouped_custom_field_joins.each { |_, v| - - sorted = v.sort_by {|a| a.updated_at }.to_a - ids_to_delete += sorted.map{|i| i.id}[0, sorted.count - 1] + sorted = v.sort_by { |a| a.updated_at }.to_a + ids_to_delete += sorted.map { |i| i.id }[0, sorted.count - 1] } ids_to_delete @@ -26,14 +23,13 @@ def self.find_multiple_custom_field_joins def self.copy_and_delete(ids_to_delete) if ids_to_delete.any? - Qx.insert_into(:custom_field_joins_backup, @columns).select(@columns).from(:custom_field_joins).where('id IN ($ids)', ids:ids_to_delete).execute - CustomFieldJoin.where('id IN (?)', ids_to_delete).delete_all + Qx.insert_into(:custom_field_joins_backup, @columns).select(@columns).from(:custom_field_joins).where("id IN ($ids)", ids: ids_to_delete).execute + CustomFieldJoin.where("id IN (?)", ids_to_delete).delete_all end - end def self.revert Qx.insert_into(:custom_field_joins, @columns).select(@columns).from(:custom_field_joins_backup).execute Qx.execute_raw("DELETE FROM custom_field_joins_backup") end -end \ No newline at end of file +end diff --git a/app/legacy_lib/email.rb b/app/legacy_lib/email.rb index d58188566..a7e8c2b28 100644 --- a/app/legacy_lib/email.rb +++ b/app/legacy_lib/email.rb @@ -1,7 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Email - - Regex ||= /\A[^ ]+@[^ ]+\.[^ ]+\z/i - #PsqlRegex ||= '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$' - + Regex ||= /\A[^ ]+@[^ ]+\.[^ ]+\z/i + # PsqlRegex ||= '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$' end diff --git a/app/legacy_lib/expired_token_error.rb b/app/legacy_lib/expired_token_error.rb index 066c32d40..31da09838 100644 --- a/app/legacy_lib/expired_token_error.rb +++ b/app/legacy_lib/expired_token_error.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ExpiredTokenError < RuntimeError -end \ No newline at end of file +end diff --git a/app/legacy_lib/export_payments.rb b/app/legacy_lib/export_payments.rb index 340580ca5..561308293 100644 --- a/app/legacy_lib/export_payments.rb +++ b/app/legacy_lib/export_payments.rb @@ -1,39 +1,37 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ExportPayments - def self.initiate_export(npo_id, params, user_id) - - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_hash: true }, - user_id: { required: true, is_integer: true }) - npo = Nonprofit.where('id = ?', npo_id).first + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_hash: true}, + user_id: {required: true, is_integer: true}) + npo = Nonprofit.where("id = ?", npo_id).first unless npo raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) end - user = User.where('id = ?', user_id).first + user = User.where("id = ?", user_id).first unless user raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) end - e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: 'ExportPayments', parameters: params.to_json) + e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: "ExportPayments", parameters: params.to_json) DelayedJobHelper.enqueue_job(ExportPayments, :run_export, [npo_id, params.to_json, user_id, e.id]) end def self.run_export(npo_id, params, user_id, export_id) # need to check that - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id, export_id: export_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_json: true }, - user_id: { required: true, is_integer: true }, - export_id: { required: true, is_integer: true }) + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id, export_id: export_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_json: true}, + user_id: {required: true, is_integer: true}, + export_id: {required: true, is_integer: true}) - params = JSON.parse(params, :object_class=> HashWithIndifferentAccess) + params = JSON.parse(params, object_class: ActiveSupport::HashWithIndifferentAccess) # verify that it's also a hash since we can't do that at once - ParamValidation.new({ params: params }, - params: { is_hash: true }) + ParamValidation.new({params: params}, + params: {is_hash: true}) begin export = Export.find(export_id) rescue ActiveRecord::RecordNotFound @@ -45,15 +43,15 @@ def self.run_export(npo_id, params, user_id, export_id) unless Nonprofit.exists?(npo_id) raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) end - user = User.where('id = ?', user_id).first + user = User.where("id = ?", user_id).first unless user raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) end - file_date = Time.now.getutc().strftime('%m-%d-%Y--%H-%M-%S') + file_date = Time.now.getutc.strftime("%m-%d-%Y--%H-%M-%S") filename = "tmp/csv-exports/payments-#{export.id}-#{file_date}.csv" - url = CHUNKED_UPLOADER.upload(filename, for_export_enumerable(npo_id, params, 15000).map{|i| i.to_csv}, :content_type => 'text/csv', content_disposition: 'attachment') + url = CHUNKED_UPLOADER.upload(filename, for_export_enumerable(npo_id, params, 15000).map { |i| i.to_csv }, content_type: "text/csv", content_disposition: "attachment") export.url = url export.status = :completed export.ended = Time.now @@ -67,8 +65,8 @@ def self.run_export(npo_id, params, user_id, export_id) export.ended = Time.now export.save! - begin - user ||= User.where('id = ?', user_id).first + begin + user ||= User.where("id = ?", user_id).first if user ExportMailer.delay.export_payments_failed_notification(export) end @@ -81,63 +79,63 @@ def self.run_export(npo_id, params, user_id, export_id) private - def self.for_export_enumerable(npo_id, query, chunk_limit=15000) - ParamValidation.new({npo_id: npo_id, query:query}, {npo_id: {required: true, is_int: true}, - query: {required:true, is_hash: true}}) + def self.for_export_enumerable(npo_id, query, chunk_limit = 15000) + ParamValidation.new({npo_id: npo_id, query: query}, {npo_id: {required: true, is_int: true}, + query: {required: true, is_hash: true}}) QexprQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| get_chunk_of_export(npo_id, query, offset, limit, skip_header) end end - def self.get_chunk_of_export(npo_id, query, offset=nil, limit=nil, skip_header=false) + def self.get_chunk_of_export(npo_id, query, offset = nil, limit = nil, skip_header = false) QexprQueryChunker.get_chunk_of_query(offset, limit, skip_header) do - expr = QueryPayments.full_search_expr(npo_id, query) - .select(*export_selects(query[:export_format_id])) - .left_outer_join('campaign_gifts', 'campaign_gifts.donation_id=donations.id') - .left_outer_join('campaign_gift_options', 'campaign_gifts.campaign_gift_option_id=campaign_gift_options.id') - .left_outer_join("(#{campaigns_with_creator_email}) AS campaigns_for_export", 'donations.campaign_id=campaigns_for_export.id') - .left_outer_join(tickets, 'tickets.payment_id=payments.id') - .left_outer_join('events events_for_export', 'events_for_export.id=tickets.event_id OR donations.event_id=events_for_export.id') - .left_outer_join('offsite_payments', 'offsite_payments.payment_id=payments.id') - .left_outer_join('misc_payment_infos', 'payments.id = misc_payment_infos.payment_id') + QueryPayments.full_search_expr(npo_id, query) + .select(*export_selects(query[:export_format_id])) + .left_outer_join("campaign_gifts", "campaign_gifts.donation_id=donations.id") + .left_outer_join("campaign_gift_options", "campaign_gifts.campaign_gift_option_id=campaign_gift_options.id") + .left_outer_join("(#{campaigns_with_creator_email}) AS campaigns_for_export", "donations.campaign_id=campaigns_for_export.id") + .left_outer_join(tickets, "tickets.payment_id=payments.id") + .left_outer_join("events events_for_export", "events_for_export.id=tickets.event_id OR donations.event_id=events_for_export.id") + .left_outer_join("offsite_payments", "offsite_payments.payment_id=payments.id") + .left_outer_join("misc_payment_infos", "payments.id = misc_payment_infos.payment_id") end end def self.export_selects(export_format_id) - if(export_format_id.present?) + if export_format_id.present? return build_export_select_using_export_format(ExportFormat.find(export_format_id)) end - ["to_char(payments.date::timestamptz at time zone COALESCE(nonprofits.timezone, \'UTC\'), 'YYYY-MM-DD HH24:MI:SS TZ') AS date", - '(payments.gross_amount / 100.0)::money::text AS gross_amount', - '(payments.fee_total / 100.0)::money::text AS fee_total', - '(payments.net_amount / 100.0)::money::text AS net_amount', - 'payments.kind AS type'] - .concat(QuerySupporters.supporter_export_selections(:anonymous)) - .concat([ - "coalesce(donations.designation, 'None') AS designation", - "#{QueryPayments.get_dedication_or_empty('type')}::text AS \"Dedication Type\"", - "#{QueryPayments.get_dedication_or_empty('name')}::text AS \"Dedicated To: Name\"", - "#{QueryPayments.get_dedication_or_empty('supporter_id')}::text AS \"Dedicated To: Supporter ID\"", - "#{QueryPayments.get_dedication_or_empty('contact', 'email')}::text AS \"Dedicated To: Email\"", - "#{QueryPayments.get_dedication_or_empty('contact', "phone")}::text AS \"Dedicated To: Phone\"", - "#{QueryPayments.get_dedication_or_empty( "contact", "address")}::text AS \"Dedicated To: Address\"", - "#{QueryPayments.get_dedication_or_empty( "note")}::text AS \"Dedicated To: Note\"", - '(donations.anonymous OR supporters.anonymous) AS "Anonymous?"', - 'donations.comment', - "coalesce(nullif(campaigns_for_export.name, ''), 'None') AS campaign", - "campaigns_for_export.id AS \"Campaign Id\"", - "coalesce(nullif(campaigns_for_export.creator_email, ''), '') AS campaign_creator_email", - "coalesce(nullif(campaign_gift_options.name, ''), 'None') AS campaign_gift_level", - 'events_for_export.name AS event_name', - 'payments.id AS payment_id', - 'offsite_payments.check_number AS check_number', - 'donations.comment AS donation_note', - "CASE WHEN payments.kind = 'RecurringDonation' - THEN to_char(donations.created_at::timestamptz at time zone COALESCE(nonprofits.timezone, \'UTC\'), 'YYYY-MM-DD HH24:MI:SS TZ') + ["to_char(payments.date::timestamptz at time zone COALESCE(nonprofits.timezone, 'UTC'), 'YYYY-MM-DD HH24:MI:SS TZ') AS date", + "(payments.gross_amount / 100.0)::money::text AS gross_amount", + "(payments.fee_total / 100.0)::money::text AS fee_total", + "(payments.net_amount / 100.0)::money::text AS net_amount", + "payments.kind AS type"] + .concat(QuerySupporters.supporter_export_selections(:anonymous)) + .concat([ + "coalesce(donations.designation, 'None') AS designation", + "#{QueryPayments.get_dedication_or_empty("type")}::text AS \"Dedication Type\"", + "#{QueryPayments.get_dedication_or_empty("name")}::text AS \"Dedicated To: Name\"", + "#{QueryPayments.get_dedication_or_empty("supporter_id")}::text AS \"Dedicated To: Supporter ID\"", + "#{QueryPayments.get_dedication_or_empty("contact", "email")}::text AS \"Dedicated To: Email\"", + "#{QueryPayments.get_dedication_or_empty("contact", "phone")}::text AS \"Dedicated To: Phone\"", + "#{QueryPayments.get_dedication_or_empty("contact", "address")}::text AS \"Dedicated To: Address\"", + "#{QueryPayments.get_dedication_or_empty("note")}::text AS \"Dedicated To: Note\"", + '(donations.anonymous OR supporters.anonymous) AS "Anonymous?"', + "donations.comment", + "coalesce(nullif(campaigns_for_export.name, ''), 'None') AS campaign", + "campaigns_for_export.id AS \"Campaign Id\"", + "coalesce(nullif(campaigns_for_export.creator_email, ''), '') AS campaign_creator_email", + "coalesce(nullif(campaign_gift_options.name, ''), 'None') AS campaign_gift_level", + "events_for_export.name AS event_name", + "payments.id AS payment_id", + "offsite_payments.check_number AS check_number", + "donations.comment AS donation_note", + "CASE WHEN payments.kind = 'RecurringDonation' + THEN to_char(donations.created_at::timestamptz at time zone COALESCE(nonprofits.timezone, 'UTC'), 'YYYY-MM-DD HH24:MI:SS TZ') ELSE '' END AS \"Recurring Donation Started At\"", - 'coalesce(nullif(misc_payment_infos.fee_covered, false), false) AS "Fee Covered by Supporter"' - ]) + 'coalesce(nullif(misc_payment_infos.fee_covered, false), false) AS "Fee Covered by Supporter"' + ]) end def self.build_export_select_using_export_format(export_format) @@ -148,59 +146,59 @@ def self.build_export_select_using_export_format(export_format) def self.build_payments_select(export_format) custom_names = build_custom_names_for_payments(export_format.custom_columns_and_values) - date_format = export_format.date_format || 'YYYY-MM-DD HH24:MI:SS TZ' - payments_select = ["to_char(payments.date::timestamptz at time zone COALESCE(nonprofits.timezone, \'UTC\'), '#{date_format}') AS #{custom_names['payments.date']}"] + date_format = export_format.date_format || "YYYY-MM-DD HH24:MI:SS TZ" + payments_select = ["to_char(payments.date::timestamptz at time zone COALESCE(nonprofits.timezone, 'UTC'), '#{date_format}') AS #{custom_names["payments.date"]}"] - if(export_format.show_currency) + if export_format.show_currency payments_select.concat([ - "#{money_with_currency('payments.gross_amount')} AS #{custom_names['payments.gross_amount']}", - "#{money_with_currency('payments.fee_total')} AS #{custom_names['payments.fee_total']}", - "#{money_with_currency('payments.net_amount')} AS #{custom_names['payments.net_amount']}" + "#{money_with_currency("payments.gross_amount")} AS #{custom_names["payments.gross_amount"]}", + "#{money_with_currency("payments.fee_total")} AS #{custom_names["payments.fee_total"]}", + "#{money_with_currency("payments.net_amount")} AS #{custom_names["payments.net_amount"]}" ]) else payments_select.concat([ - "#{money_without_currency('payments.gross_amount')} AS #{custom_names['payments.gross_amount']}", - "#{money_without_currency('payments.fee_total')} AS #{custom_names['payments.fee_total']}", - "#{money_without_currency('payments.net_amount')} AS #{custom_names['payments.net_amount']}" + "#{money_without_currency("payments.gross_amount")} AS #{custom_names["payments.gross_amount"]}", + "#{money_without_currency("payments.fee_total")} AS #{custom_names["payments.fee_total"]}", + "#{money_without_currency("payments.net_amount")} AS #{custom_names["payments.net_amount"]}" ]) end - payments_select.concat([build_custom_value_clause('payments.kind', export_format.custom_columns_and_values, custom_names['payments.kind'])]) + payments_select.concat([build_custom_value_clause("payments.kind", export_format.custom_columns_and_values, custom_names["payments.kind"])]) end def self.build_donations_and_campaigns_select(export_format) custom_columns_and_values = export_format.custom_columns_and_values custom_names = build_custom_names_for_donations_and_campaigns(custom_columns_and_values) - date_format = export_format.date_format || 'YYYY-MM-DD HH24:MI:SS TZ' + date_format = export_format.date_format || "YYYY-MM-DD HH24:MI:SS TZ" [ - build_custom_value_clause('donations.designation', custom_columns_and_values, custom_names['donations.designation'], "coalesce(donations.designation, 'None')"), - "#{QueryPayments.get_dedication_or_empty('type')}::text AS \"Dedication Type\"", - "#{QueryPayments.get_dedication_or_empty('name')}::text AS \"Dedicated To: Name\"", - "#{QueryPayments.get_dedication_or_empty('supporter_id')}::text AS \"Dedicated To: Supporter ID\"", - "#{QueryPayments.get_dedication_or_empty('contact', 'email')}::text AS \"Dedicated To: Email\"", - "#{QueryPayments.get_dedication_or_empty('contact', "phone")}::text AS \"Dedicated To: Phone\"", - "#{QueryPayments.get_dedication_or_empty( "contact", "address")}::text AS \"Dedicated To: Address\"", - "#{QueryPayments.get_dedication_or_empty( "note")}::text AS \"Dedicated To: Note\"", - build_custom_value_clause('donations.anonymous OR supporters.anonymous', custom_columns_and_values, custom_names['donations.anonymous OR supporters.anonymous'], '(donations.anonymous OR supporters.anonymous)'), - build_custom_value_clause('donations.comment', custom_columns_and_values, '"Comment"'), - build_custom_value_clause('campaigns_for_export.name', custom_columns_and_values, custom_names['campaigns_for_export.name'], "coalesce(nullif(campaigns_for_export.name, ''), 'None')"), - "campaigns_for_export.id AS #{custom_names['campaigns_for_export.id']}", - "coalesce(nullif(campaigns_for_export.creator_email, ''), '') AS #{custom_names['campaigns_for_export.creator_email']}", - build_custom_value_clause('campaign_gift_options.name', custom_columns_and_values, custom_names['campaign_gift_options.name'], "coalesce(nullif(campaign_gift_options.name, ''), 'None')"), - build_custom_value_clause('campaigns_for_export.name', custom_columns_and_values, custom_names['campaigns_for_export.name'], "coalesce(nullif(campaign_gift_options.name, ''), 'None')"), - build_custom_value_clause('events_for_export.name', custom_columns_and_values, custom_names['events_for_export.name']), - "payments.id AS #{custom_names['payments.id']}", - "offsite_payments.check_number AS #{custom_names['offsite_payments.check_number']}", - build_custom_value_clause('donations.comment', custom_columns_and_values, custom_names['donations.comment']), + build_custom_value_clause("donations.designation", custom_columns_and_values, custom_names["donations.designation"], "coalesce(donations.designation, 'None')"), + "#{QueryPayments.get_dedication_or_empty("type")}::text AS \"Dedication Type\"", + "#{QueryPayments.get_dedication_or_empty("name")}::text AS \"Dedicated To: Name\"", + "#{QueryPayments.get_dedication_or_empty("supporter_id")}::text AS \"Dedicated To: Supporter ID\"", + "#{QueryPayments.get_dedication_or_empty("contact", "email")}::text AS \"Dedicated To: Email\"", + "#{QueryPayments.get_dedication_or_empty("contact", "phone")}::text AS \"Dedicated To: Phone\"", + "#{QueryPayments.get_dedication_or_empty("contact", "address")}::text AS \"Dedicated To: Address\"", + "#{QueryPayments.get_dedication_or_empty("note")}::text AS \"Dedicated To: Note\"", + build_custom_value_clause("donations.anonymous OR supporters.anonymous", custom_columns_and_values, custom_names["donations.anonymous OR supporters.anonymous"], "(donations.anonymous OR supporters.anonymous)"), + build_custom_value_clause("donations.comment", custom_columns_and_values, '"Comment"'), + build_custom_value_clause("campaigns_for_export.name", custom_columns_and_values, custom_names["campaigns_for_export.name"], "coalesce(nullif(campaigns_for_export.name, ''), 'None')"), + "campaigns_for_export.id AS #{custom_names["campaigns_for_export.id"]}", + "coalesce(nullif(campaigns_for_export.creator_email, ''), '') AS #{custom_names["campaigns_for_export.creator_email"]}", + build_custom_value_clause("campaign_gift_options.name", custom_columns_and_values, custom_names["campaign_gift_options.name"], "coalesce(nullif(campaign_gift_options.name, ''), 'None')"), + build_custom_value_clause("campaigns_for_export.name", custom_columns_and_values, custom_names["campaigns_for_export.name"], "coalesce(nullif(campaign_gift_options.name, ''), 'None')"), + build_custom_value_clause("events_for_export.name", custom_columns_and_values, custom_names["events_for_export.name"]), + "payments.id AS #{custom_names["payments.id"]}", + "offsite_payments.check_number AS #{custom_names["offsite_payments.check_number"]}", + build_custom_value_clause("donations.comment", custom_columns_and_values, custom_names["donations.comment"]), "CASE WHEN payments.kind = 'RecurringDonation' - THEN to_char(donations.created_at::timestamptz at time zone COALESCE(nonprofits.timezone, \'UTC\'), '#{date_format}') - ELSE '' END AS #{custom_names['donations.created_at']}", - build_custom_value_clause('misc_payment_infos.fee_covered', custom_columns_and_values, custom_names['misc_payment_infos.fee_covered'], "coalesce(nullif(misc_payment_infos.fee_covered, false), false)") + THEN to_char(donations.created_at::timestamptz at time zone COALESCE(nonprofits.timezone, 'UTC'), '#{date_format}') + ELSE '' END AS #{custom_names["donations.created_at"]}", + build_custom_value_clause("misc_payment_infos.fee_covered", custom_columns_and_values, custom_names["misc_payment_infos.fee_covered"], "coalesce(nullif(misc_payment_infos.fee_covered, false), false)") ] end def self.build_custom_value_clause(column_name, custom_columns_and_values, custom_column_name, column_treatment = column_name) - custom_values = custom_columns_and_values&.dig(column_name)&.dig('custom_values') - if(custom_values.present?) + custom_values = custom_columns_and_values&.dig(column_name)&.dig("custom_values") + if custom_values.present? return build_custom_values_switch_case(custom_values, column_treatment, custom_column_name) end "#{column_treatment} AS #{custom_column_name}" @@ -216,32 +214,32 @@ def self.build_custom_values_switch_case(custom_values, column_name, custom_colu def self.build_custom_names_for_payments(custom_names) { - 'payments.date' => custom_names&.dig('payments.date')&.dig('custom_name') || 'date', - 'payments.gross_amount' => custom_names&.dig('payments.gross_amount')&.dig('custom_name') || 'gross_amount', - 'payments.fee_total' => custom_names&.dig('payments.fee_total')&.dig('custom_name') || 'fee_total', - 'payments.net_amount' => custom_names&.dig('payments.net_amount')&.dig('custom_name') || 'net_amount', - 'payments.kind' => custom_names&.dig('payments.kind')&.dig('custom_name') || 'type' + "payments.date" => custom_names&.dig("payments.date")&.dig("custom_name") || "date", + "payments.gross_amount" => custom_names&.dig("payments.gross_amount")&.dig("custom_name") || "gross_amount", + "payments.fee_total" => custom_names&.dig("payments.fee_total")&.dig("custom_name") || "fee_total", + "payments.net_amount" => custom_names&.dig("payments.net_amount")&.dig("custom_name") || "net_amount", + "payments.kind" => custom_names&.dig("payments.kind")&.dig("custom_name") || "type" } end def self.build_custom_names_for_donations_and_campaigns(custom_names) { - 'donations.designation' => custom_names&.dig('donations.designation')&.dig('custom_name') || 'designation', - 'donations.anonymous OR supporters.anonymous' => ( - custom_names&.dig('donations.anonymous OR supporters.anonymous') || - custom_names&.dig('donations.anonymous') || - custom_names&.dig('supporters.anonymous') - )&.dig('custom_name') || '"Anonymous?"', - 'campaigns_for_export.name' => custom_names&.dig('campaigns_for_export.name')&.dig('custom_name') || 'campaign', - 'campaigns_for_export.id' => custom_names&.dig('campaigns_for_export.id')&.dig('custom_name') || '"Campaign Id"', - 'campaigns_for_export.creator_email' => custom_names&.dig('campaigns_for_export.creator_email')&.dig('custom_name') || 'campaign_creator_email', - 'campaign_gift_options.name' => custom_names&.dig('campaign_gift_options.name')&.dig('custom_name') || 'campaign_gift_level', - 'events_for_export.name' => custom_names&.dig('events_for_export.name')&.dig('custom_name') || 'event_name', - 'payments.id' => custom_names&.dig('payments.id')&.dig('custom_name') || 'payment_id', - 'offsite_payments.check_number' => custom_names&.dig('offsite_payments.check_number')&.dig('custom_name') || 'check_number', - 'donations.comment' => custom_names&.dig('donations.comment')&.dig('custom_name') || 'donation_note', - 'donations.created_at' => custom_names&.dig('donations.created_at')&.dig('custom_name') || '"Recurring Donation Started At"', - 'misc_payment_infos.fee_covered' => custom_names&.dig('misc_payment_infos.fee_covered')&.dig('custom_name') || '"Fee Covered by Supporter"' + "donations.designation" => custom_names&.dig("donations.designation")&.dig("custom_name") || "designation", + "donations.anonymous OR supporters.anonymous" => ( + custom_names&.dig("donations.anonymous OR supporters.anonymous") || + custom_names&.dig("donations.anonymous") || + custom_names&.dig("supporters.anonymous") + )&.dig("custom_name") || '"Anonymous?"', + "campaigns_for_export.name" => custom_names&.dig("campaigns_for_export.name")&.dig("custom_name") || "campaign", + "campaigns_for_export.id" => custom_names&.dig("campaigns_for_export.id")&.dig("custom_name") || '"Campaign Id"', + "campaigns_for_export.creator_email" => custom_names&.dig("campaigns_for_export.creator_email")&.dig("custom_name") || "campaign_creator_email", + "campaign_gift_options.name" => custom_names&.dig("campaign_gift_options.name")&.dig("custom_name") || "campaign_gift_level", + "events_for_export.name" => custom_names&.dig("events_for_export.name")&.dig("custom_name") || "event_name", + "payments.id" => custom_names&.dig("payments.id")&.dig("custom_name") || "payment_id", + "offsite_payments.check_number" => custom_names&.dig("offsite_payments.check_number")&.dig("custom_name") || "check_number", + "donations.comment" => custom_names&.dig("donations.comment")&.dig("custom_name") || "donation_note", + "donations.created_at" => custom_names&.dig("donations.created_at")&.dig("custom_name") || '"Recurring Donation Started At"', + "misc_payment_infos.fee_covered" => custom_names&.dig("misc_payment_infos.fee_covered")&.dig("custom_name") || '"Fee Covered by Supporter"' } end @@ -256,10 +254,10 @@ def self.money_without_currency(column) def self.campaigns_with_creator_email Qexpr .new - .select('campaigns.*, users.email AS creator_email') + .select("campaigns.*, users.email AS creator_email") .from(:campaigns) .left_outer_join(:profiles, "profiles.id = campaigns.profile_id") - .left_outer_join(:users, 'users.id = profiles.user_id') + .left_outer_join(:users, "users.id = profiles.user_id") end def self.tickets diff --git a/app/legacy_lib/export_recurring_donations.rb b/app/legacy_lib/export_recurring_donations.rb index e33a5150d..2bb4e2651 100644 --- a/app/legacy_lib/export_recurring_donations.rb +++ b/app/legacy_lib/export_recurring_donations.rb @@ -1,39 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ExportRecurringDonations - def self.initiate_export(npo_id, params, user_ids, export_type = :requested_by_user_through_ui) - ParamValidation.new({ npo_id: npo_id, params: params, user_ids: user_ids }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_hash: true }, - user_ids: { required: true, is_array: true }) - npo = Nonprofit.where('id = ?', npo_id).first + ParamValidation.new({npo_id: npo_id, params: params, user_ids: user_ids}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_hash: true}, + user_ids: {required: true, is_array: true}) + npo = Nonprofit.where("id = ?", npo_id).first unless npo raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) end user_ids.each do |user_id| - user = User.where('id = ?', user_id).first + user = User.where("id = ?", user_id).first unless user raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) end - e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: 'ExportRecurringDonations', parameters: params.to_json) + e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: "ExportRecurringDonations", parameters: params.to_json) DelayedJobHelper.enqueue_job(ExportRecurringDonations, :run_export, [npo_id, params.to_json, user_id, e.id, export_type]) end end def self.run_export(npo_id, params, user_id, export_id, export_type = :requested_by_user_through_ui) # need to check that - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id, export_id: export_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_json: true }, - user_id: { required: true, is_integer: true }, - export_id: { required: true, is_integer: true }) + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id, export_id: export_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_json: true}, + user_id: {required: true, is_integer: true}, + export_id: {required: true, is_integer: true}) - params = JSON.parse(params, :object_class=> HashWithIndifferentAccess) + params = JSON.parse(params, object_class: ActiveSupport::HashWithIndifferentAccess) # verify that it's also a hash since we can't do that at once - ParamValidation.new({ params: params }, - params: { is_hash: true }) + ParamValidation.new({params: params}, + params: {is_hash: true}) begin export = Export.find(export_id) rescue ActiveRecord::RecordNotFound @@ -45,15 +44,15 @@ def self.run_export(npo_id, params, user_id, export_id, export_type = :requested unless Nonprofit.exists?(npo_id) raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) end - user = User.where('id = ?', user_id).first + user = User.where("id = ?", user_id).first unless user raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) end - file_date = Time.now.getutc().strftime('%m-%d-%Y--%H-%M-%S') + file_date = Time.now.getutc.strftime("%m-%d-%Y--%H-%M-%S") filename = "tmp/csv-exports/recurring_donations-#{export.id}-#{file_date}.csv" - url = CHUNKED_UPLOADER.upload(filename, QueryRecurringDonations.for_export_enumerable(npo_id, params, 15000).map{|i| i.to_csv}, :content_type => 'text/csv', content_disposition: 'attachment') + url = CHUNKED_UPLOADER.upload(filename, QueryRecurringDonations.for_export_enumerable(npo_id, params, 15000).map { |i| i.to_csv }, content_type: "text/csv", content_disposition: "attachment") export.url = url export.status = :completed export.ended = Time.now @@ -74,47 +73,42 @@ def self.run_export(npo_id, params, user_id, export_id, export_type = :requested raise e end - def self.run_export_for_active_recurring_donations_to_csv(nonprofit_s3_key, filename, export) if filename.blank? - file_date = Time.now.getutc().strftime('%m-%d-%Y--%H-%M-%S') + file_date = Time.now.getutc.strftime("%m-%d-%Y--%H-%M-%S") filename = "tmp/json-exports/recurring_donations-#{export.id}-#{file_date}.csv" end bucket = get_bucket(nonprofit_s3_key) object = bucket.object(filename) - object.upload_stream(temp_file:true, acl: 'private', content_type: 'text/csv', content_disposition: 'attachment') do |write_stream| + object.upload_stream(temp_file: true, acl: "private", content_type: "text/csv", content_disposition: "attachment") do |write_stream| write_stream << QueryRecurringDonations.get_active_recurring_for_an_org(export.nonprofit) end object.public_url.to_s - end def self.run_export_for_started_recurring_donations_to_csv(nonprofit_s3_key, filename, export) if filename.blank? - file_date = Time.now.getutc().strftime('%m-%d-%Y--%H-%M-%S') + file_date = Time.now.getutc.strftime("%m-%d-%Y--%H-%M-%S") filename = "tmp/json-exports/recurring_donations-#{export.id}-#{file_date}.csv" end - bucket = get_bucket(nonprofit_s3_key) object = bucket.object(filename) - object.upload_stream(temp_file:true, acl: 'private', content_type: 'text/csv', content_disposition: 'attachment') do |write_stream| + object.upload_stream(temp_file: true, acl: "private", content_type: "text/csv", content_disposition: "attachment") do |write_stream| write_stream << QueryRecurringDonations.get_new_recurring_for_an_org_during_a_period(export.nonprofit) end object.public_url.to_s - end - def self.get_bucket(nonprofit_s3_key) if nonprofit_s3_key.present? nonprofit_s3_key.s3_bucket else s3 = ::Aws::S3::Resource.new - bucket = s3.bucket(ChunkedUploader::S3::S3_BUCKET_NAME) + s3.bucket(ChunkedUploader::S3::S3_BUCKET_NAME) end end diff --git a/app/legacy_lib/export_supporter_notes.rb b/app/legacy_lib/export_supporter_notes.rb index ea3486f23..46ba40407 100644 --- a/app/legacy_lib/export_supporter_notes.rb +++ b/app/legacy_lib/export_supporter_notes.rb @@ -1,74 +1,73 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ExportSupporterNotes - def self.initiate_export(npo_id, params, user_id) + def self.initiate_export(npo_id, params, user_id) + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_hash: true}, + user_id: {required: true, is_integer: true}) + npo = Nonprofit.where("id = ?", npo_id).first + unless npo + raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) + end + user = User.where("id = ?", user_id).first + unless user + raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) + end - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_hash: true }, - user_id: { required: true, is_integer: true }) - npo = Nonprofit.where('id = ?', npo_id).first - unless npo - raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) - end - user = User.where('id = ?', user_id).first - unless user - raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) - end - - e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: 'ExportSupporterNotes', parameters: params.to_json) - - DelayedJobHelper.enqueue_job(ExportSupporterNotes, :run_export, [npo_id, params.to_json, user_id, e.id]) - end - - def self.run_export(npo_id, params, user_id, export_id) - # need to check that - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id, export_id: export_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_json: true }, - user_id: { required: true, is_integer: true }, - export_id: { required: true, is_integer: true }) - - params = JSON.parse(params, :object_class=> HashWithIndifferentAccess) - # verify that it's also a hash since we can't do that at once - ParamValidation.new({ params: params }, - params: { is_hash: true }) - begin - export = Export.find(export_id) - rescue ActiveRecord::RecordNotFound - raise ParamValidation::ValidationError.new("Export #{export_id} doesn't exist!", key: :export_id) - end - export.status = :started - export.save! - - unless Nonprofit.exists?(npo_id) - raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) - end - user = User.where('id = ?', user_id).first - unless user - raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) - end - - file_date = Time.now.getutc().strftime('%m-%d-%Y--%H-%M-%S') - filename = "tmp/csv-exports/supporters-notes-#{export.id}-#{file_date}.csv" - - url = CHUNKED_UPLOADER.upload(filename, QuerySupporters.supporter_note_export_enumerable(npo_id, params, 15000).map{|i| i.to_csv}, content_type: 'text/csv', content_disposition: 'attachment') - export.url = url - export.status = :completed - export.ended = Time.now - export.save! - - JobQueue.queue(JobTypes::ExportSupporterNotesCompletedJob, export) - rescue => e - if export - export.status = :failed - export.exception = e.to_s - export.ended = Time.now - export.save! - if user - JobQueue.queue(JobTypes::ExportSupporterNotesFailedJob, export) - end - raise e - end - raise e + e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: "ExportSupporterNotes", parameters: params.to_json) + + DelayedJobHelper.enqueue_job(ExportSupporterNotes, :run_export, [npo_id, params.to_json, user_id, e.id]) + end + + def self.run_export(npo_id, params, user_id, export_id) + # need to check that + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id, export_id: export_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_json: true}, + user_id: {required: true, is_integer: true}, + export_id: {required: true, is_integer: true}) + + params = JSON.parse(params, object_class: ActiveSupport::HashWithIndifferentAccess) + # verify that it's also a hash since we can't do that at once + ParamValidation.new({params: params}, + params: {is_hash: true}) + begin + export = Export.find(export_id) + rescue ActiveRecord::RecordNotFound + raise ParamValidation::ValidationError.new("Export #{export_id} doesn't exist!", key: :export_id) + end + export.status = :started + export.save! + + unless Nonprofit.exists?(npo_id) + raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) + end + user = User.where("id = ?", user_id).first + unless user + raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) + end + + file_date = Time.now.getutc.strftime("%m-%d-%Y--%H-%M-%S") + filename = "tmp/csv-exports/supporters-notes-#{export.id}-#{file_date}.csv" + + url = CHUNKED_UPLOADER.upload(filename, QuerySupporters.supporter_note_export_enumerable(npo_id, params, 15000).map { |i| i.to_csv }, content_type: "text/csv", content_disposition: "attachment") + export.url = url + export.status = :completed + export.ended = Time.now + export.save! + + JobQueue.queue(JobTypes::ExportSupporterNotesCompletedJob, export) + rescue => e + if export + export.status = :failed + export.exception = e.to_s + export.ended = Time.now + export.save! + if user + JobQueue.queue(JobTypes::ExportSupporterNotesFailedJob, export) end -end \ No newline at end of file + raise e + end + raise e + end +end diff --git a/app/legacy_lib/export_supporters.rb b/app/legacy_lib/export_supporters.rb index a13683b11..0cc94c632 100644 --- a/app/legacy_lib/export_supporters.rb +++ b/app/legacy_lib/export_supporters.rb @@ -1,36 +1,35 @@ module ExportSupporters def self.initiate_export(npo_id, params, user_id) - - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_hash: true }, - user_id: { required: true, is_integer: true }) - npo = Nonprofit.where('id = ?', npo_id).first + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_hash: true}, + user_id: {required: true, is_integer: true}) + npo = Nonprofit.where("id = ?", npo_id).first unless npo raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) end - user = User.where('id = ?', user_id).first + user = User.where("id = ?", user_id).first unless user raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) end - e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: 'ExportSupporters', parameters: params.to_json) + e = Export.create(nonprofit: npo, user: user, status: :queued, export_type: "ExportSupporters", parameters: params.to_json) DelayedJobHelper.enqueue_job(ExportSupporters, :run_export, [npo_id, params.to_json, user_id, e.id]) end def self.run_export(npo_id, params, user_id, export_id) # need to check that - ParamValidation.new({ npo_id: npo_id, params: params, user_id: user_id, export_id: export_id }, - npo_id: { required: true, is_integer: true }, - params: { required: true, is_json: true }, - user_id: { required: true, is_integer: true }, - export_id: { required: true, is_integer: true }) + ParamValidation.new({npo_id: npo_id, params: params, user_id: user_id, export_id: export_id}, + npo_id: {required: true, is_integer: true}, + params: {required: true, is_json: true}, + user_id: {required: true, is_integer: true}, + export_id: {required: true, is_integer: true}) - params = JSON.parse(params, :object_class=> HashWithIndifferentAccess) + params = JSON.parse(params, object_class: ActiveSupport::HashWithIndifferentAccess) # verify that it's also a hash since we can't do that at once - ParamValidation.new({ params: params }, - params: { is_hash: true }) + ParamValidation.new({params: params}, + params: {is_hash: true}) begin export = Export.find(export_id) rescue ActiveRecord::RecordNotFound @@ -42,14 +41,14 @@ def self.run_export(npo_id, params, user_id, export_id) unless Nonprofit.exists?(npo_id) raise ParamValidation::ValidationError.new("Nonprofit #{npo_id} doesn't exist!", key: :npo_id) end - user = User.where('id = ?', user_id).first + user = User.where("id = ?", user_id).first unless user raise ParamValidation::ValidationError.new("User #{user_id} doesn't exist!", key: :user_id) end - file_date = Time.now.getutc().strftime('%m-%d-%Y--%H-%M-%S') + file_date = Time.now.getutc.strftime("%m-%d-%Y--%H-%M-%S") filename = "tmp/csv-exports/supporters-#{export.id}-#{file_date}.csv" - url = CHUNKED_UPLOADER.upload(filename, QuerySupporters.for_export_enumerable(npo_id, params, 15000).map{|i| i.to_csv}, content_type: 'text/csv', content_disposition: 'attachment') + url = CHUNKED_UPLOADER.upload(filename, QuerySupporters.for_export_enumerable(npo_id, params, 15000).map { |i| i.to_csv }, content_type: "text/csv", content_disposition: "attachment") export.url = url export.status = :completed export.ended = Time.now @@ -69,4 +68,4 @@ def self.run_export(npo_id, params, user_id, export_id) end raise e end -end \ No newline at end of file +end diff --git a/app/legacy_lib/fetch_background_image.rb b/app/legacy_lib/fetch_background_image.rb index 79492cbd2..5a0962854 100644 --- a/app/legacy_lib/fetch_background_image.rb +++ b/app/legacy_lib/fetch_background_image.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchBackgroundImage - - def self.with_model(model) - return model.background_image_url(:normal) unless model.background_image.file.nil? - end + def self.with_model(model) + model.background_image_url(:normal) unless model.background_image.file.nil? + end end diff --git a/app/legacy_lib/fetch_campaign.rb b/app/legacy_lib/fetch_campaign.rb index 62c0a2e19..5e80e1acc 100644 --- a/app/legacy_lib/fetch_campaign.rb +++ b/app/legacy_lib/fetch_campaign.rb @@ -1,15 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchCampaign - - def self.with_params(params, nonprofit=nil) - nonprofit ||= FetchNonprofit.with_params(params) - if params[:campaign_slug] - return nonprofit.campaigns.where(slug: params[:campaign_slug]).last - elsif params[:campaign_id] || params[:id] - return nonprofit.campaigns.find(params[:campaign_id] || params[:id]) - end - end - + def self.with_params(params, nonprofit = nil) + nonprofit ||= FetchNonprofit.with_params(params) + if params[:campaign_slug] + nonprofit.campaigns.where(slug: params[:campaign_slug]).last + elsif params[:campaign_id] || params[:id] + nonprofit.campaigns.find(params[:campaign_id] || params[:id]) + end + end end - - diff --git a/app/legacy_lib/fetch_event.rb b/app/legacy_lib/fetch_event.rb index cf8a1a9ca..13a815171 100644 --- a/app/legacy_lib/fetch_event.rb +++ b/app/legacy_lib/fetch_event.rb @@ -1,14 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchEvent - - def self.with_params(params, nonprofit=nil) - nonprofit ||= FetchNonprofit.with_params(params) - if params[:event_slug] - return nonprofit.events.find_by_slug(params[:event_slug]) - elsif params[:event_id] || params[:id] - return nonprofit.events.find(params[:event_id] || params[:id]) - end - end - + def self.with_params(params, nonprofit = nil) + nonprofit ||= FetchNonprofit.with_params(params) + if params[:event_slug] + nonprofit.events.find_by_slug(params[:event_slug]) + elsif params[:event_id] || params[:id] + nonprofit.events.find(params[:event_id] || params[:id]) + end + end end - diff --git a/app/legacy_lib/fetch_miscellaneous_np_info.rb b/app/legacy_lib/fetch_miscellaneous_np_info.rb index 85510589b..50064011a 100644 --- a/app/legacy_lib/fetch_miscellaneous_np_info.rb +++ b/app/legacy_lib/fetch_miscellaneous_np_info.rb @@ -1,8 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchMiscellaneousNpInfo def self.fetch(np_id) - ParamValidation.new({np_id: np_id}, np_id: {:required => true, :is_integer => true}) + ParamValidation.new({np_id: np_id}, np_id: {required: true, is_integer: true}) raise ParamValidation::ValidationError.new("Nonprofit #{np_id} does not exist", {key: :np_id}) unless Nonprofit.exists?(np_id) - MiscellaneousNpInfo.where('nonprofit_id = ?', np_id).first_or_initialize + MiscellaneousNpInfo.where("nonprofit_id = ?", np_id).first_or_initialize end -end \ No newline at end of file +end diff --git a/app/legacy_lib/fetch_nonprofit.rb b/app/legacy_lib/fetch_nonprofit.rb index a1f8e9c6f..1ec9cdb02 100644 --- a/app/legacy_lib/fetch_nonprofit.rb +++ b/app/legacy_lib/fetch_nonprofit.rb @@ -1,15 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchNonprofit - - def self.with_params(params, administered_nonprofit=nil) - if params[:state_code] && params[:city] && params[:name] - return Nonprofit.find_via_cached_key_for_location(params[:state_code], params[:city], params[:name]) - elsif params[:nonprofit_id] || params[:id] - return Nonprofit.find_via_cached_id(params[:nonprofit_id] || params[:id]) + def self.with_params(params, administered_nonprofit = nil) + if params[:state_code] && params[:city] && params[:name] + Nonprofit.find_via_cached_key_for_location(params[:state_code], params[:city], params[:name]) + elsif params[:nonprofit_id] || params[:id] + Nonprofit.find_via_cached_id(params[:nonprofit_id] || params[:id]) elsif administered_nonprofit administered_nonprofit - end - end - + end + end end - diff --git a/app/legacy_lib/fetch_nonprofit_email.rb b/app/legacy_lib/fetch_nonprofit_email.rb index dc11e78d8..584bfb4e1 100644 --- a/app/legacy_lib/fetch_nonprofit_email.rb +++ b/app/legacy_lib/fetch_nonprofit_email.rb @@ -1,13 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchNonprofitEmail + def self.with_charge charge + nonprofit = charge.nonprofit + nonprofit.email.presence || Settings.mailer.email + end - def self.with_charge charge - nonprofit = charge.nonprofit - nonprofit.email.blank? ? Settings.mailer.email : nonprofit.email - end - - def self.with_donation donation - nonprofit = donation.nonprofit - nonprofit.email.blank? ? Settings.mailer.email : nonprofit.email - end + def self.with_donation donation + nonprofit = donation.nonprofit + nonprofit.email.presence || Settings.mailer.email + end end diff --git a/app/legacy_lib/fetch_stripe_account.rb b/app/legacy_lib/fetch_stripe_account.rb index 0e7f8aa31..59c5e0664 100644 --- a/app/legacy_lib/fetch_stripe_account.rb +++ b/app/legacy_lib/fetch_stripe_account.rb @@ -2,14 +2,12 @@ # Retrive a stripe account object, catching any errors module FetchStripeAccount - - def self.with_account_id(stripe_account_id) - begin - stripe_acct = Stripe::Account.retrieve(stripe_account_id) - rescue - stripe_acct = nil - end - return stripe_acct - end - + def self.with_account_id(stripe_account_id) + begin + stripe_acct = Stripe::Account.retrieve(stripe_account_id) + rescue + stripe_acct = nil + end + stripe_acct + end end diff --git a/app/legacy_lib/fetch_todo_status.rb b/app/legacy_lib/fetch_todo_status.rb index 1bd09463d..213514d0e 100644 --- a/app/legacy_lib/fetch_todo_status.rb +++ b/app/legacy_lib/fetch_todo_status.rb @@ -1,28 +1,27 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FetchTodoStatus + def self.for_profile(np) + { + has_logo: np.logo?, + has_background: np.background_image?, + has_summary: np.summary?, + has_image: np.main_image?, + has_highlight: np.has_achievements?, + has_services: np.full_description? + } + end - def self.for_profile(np) - { - has_logo: np.logo?, - has_background: np.background_image?, - has_summary: np.summary?, - has_image: np.main_image?, - has_highlight: np.has_achievements?, - has_services: np.full_description? - } - end - - def self.for_dashboard(np) - { - has_campaign: np.campaigns.any?, - has_event: np.events.any?, - has_donation: np.donations.any?, - has_branding: np.brand_color?, - has_bank: np.bank_account.present?, - is_paying: np.billing_plan.present?, - has_imported: np.supporters.pluck(:imported_at).any?, - is_verified: np.stripe_account&.verification_status == :verified && np.bank_account.present?, - has_thank_you: np.thank_you_note.present? - } - end + def self.for_dashboard(np) + { + has_campaign: np.campaigns.any?, + has_event: np.events.any?, + has_donation: np.donations.any?, + has_branding: np.brand_color?, + has_bank: np.bank_account.present?, + is_paying: np.billing_plan.present?, + has_imported: np.supporters.pluck(:imported_at).any?, + is_verified: np.stripe_account&.verification_status == :verified && np.bank_account.present?, + has_thank_you: np.thank_you_note.present? + } + end end diff --git a/app/legacy_lib/format/address.rb b/app/legacy_lib/format/address.rb index 656d6aefa..7d495c6b6 100644 --- a/app/legacy_lib/format/address.rb +++ b/app/legacy_lib/format/address.rb @@ -1,23 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Format::Address - - def self.full_address(street, city, state, zip=nil) - # Albuquerque | NM | Albuquerque NM | 1234 Street Ln, Albuquerque NM - [[street, city].compact.join(", "), state, zip].compact.join(' ') - end + def self.full_address(street, city, state, zip = nil) + # Albuquerque | NM | Albuquerque NM | 1234 Street Ln, Albuquerque NM + [[street, city].compact.join(", "), state, zip].compact.join(" ") + end - def self.city_and_state(city,state) - [city, state].join(', ') if !city.blank? && !state.blank? - end + def self.city_and_state(city, state) + [city, state].join(", ") if !city.blank? && !state.blank? + end - def self.city_or_state(city,state) - city_and_state(city,state) || city || state - end - - def self.with_supporter(s) - return '' if s.nil? - [[s.address, s.city, s.state_code].reject(&:blank?).join(", "), s.zip_code].reject(&:blank?).join(" ") - end + def self.city_or_state(city, state) + city_and_state(city, state) || city || state + end + def self.with_supporter(s) + return "" if s.nil? + [[s.address, s.city, s.state_code].reject(&:blank?).join(", "), s.zip_code].reject(&:blank?).join(" ") + end end - diff --git a/app/legacy_lib/format/csv.rb b/app/legacy_lib/format/csv.rb index 75db7c9de..4c2b2f9a3 100644 --- a/app/legacy_lib/format/csv.rb +++ b/app/legacy_lib/format/csv.rb @@ -1,34 +1,32 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'csv' -require 'format/currency' +require "csv" +require "format/currency" module Format module Csv - # Convert an array of hashes of data into a csv # @param [Array] an array of hashes. The hash keys of the first item in the array become the CSV titles # @return [String] # @option opts [TrueClass,FalseClass] titleize_header (true) Whether to titleize headers, i.e. whether to turn "supporter_email" into "Supporter Email" def self.from_data(arr, titleize_header: true) - return CSV.generate do |csv| - csv << arr.first.keys.map{|k| titleize_header ? k.to_s.titleize : k.to_s} - arr.each{|h| csv << h.values} + CSV.generate do |csv| + csv << arr.first.keys.map { |k| titleize_header ? k.to_s.titleize : k.to_s } + arr.each { |h| csv << h.values } end end def self.from_vectors(vecs) - return CSV.generate do |csv| - csv << vecs.first.to_a.map{|k| k.to_s.titleize} - vecs.drop(1).each{|v| csv << v.to_a} + CSV.generate do |csv| + csv << vecs.first.to_a.map { |k| k.to_s.titleize } + vecs.drop(1).each { |v| csv << v.to_a } end end def self.from_array(arr) - return CSV.generate do |csv| - csv << arr.first.map{|h| h.to_s.titleize} - arr.drop(1).each{|row| csv << (row||[])} + CSV.generate do |csv| + csv << arr.first.map { |h| h.to_s.titleize } + arr.drop(1).each { |row| csv << (row || []) } end end - end end diff --git a/app/legacy_lib/format/currency.rb b/app/legacy_lib/format/currency.rb index b64a6bdb8..3e1415647 100644 --- a/app/legacy_lib/format/currency.rb +++ b/app/legacy_lib/format/currency.rb @@ -1,21 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Format::Currency + # Converts currency units into subunits. + # @param [String] units + # @return [Integer] + def self.dollars_to_cents(units) + (units.delete(",").gsub(Settings.intntl.currencies[0], "").to_f * 100).to_i + end - - # Converts currency units into subunits. - # @param [String] units - # @return [Integer] - def self.dollars_to_cents(units) - return (units.gsub(',','').gsub(Settings.intntl.currencies[0],'').to_f * 100).to_i - end - - # Converts currency subunits into units. - # @param [Integer] subunits - # @return [String] - def self.cents_to_dollars(subunits) - return (subunits.to_f / 100.0).to_s - .gsub(/^(\d+)\.0$/, '\1') # remove trailing zero if no decimals (eg. "1.0" -> "1") - .gsub(/^(\d+)\.(\d)$/, '\1.\20') # add a second zero if single decimal (eg. "9.9" -> "9.90") - end - + # Converts currency subunits into units. + # @param [Integer] subunits + # @return [String] + def self.cents_to_dollars(subunits) + (subunits.to_f / 100.0).to_s + .gsub(/^(\d+)\.0$/, '\1') # remove trailing zero if no decimals (eg. "1.0" -> "1") + .gsub(/^(\d+)\.(\d)$/, '\1.\20') # add a second zero if single decimal (eg. "9.9" -> "9.90") + end end diff --git a/app/legacy_lib/format/date.rb b/app/legacy_lib/format/date.rb index 807af53aa..0486d55ed 100644 --- a/app/legacy_lib/format/date.rb +++ b/app/legacy_lib/format/date.rb @@ -1,58 +1,56 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'chronic' +require "chronic" module Format::Date - def self.parse(str) Chronic.parse(str) end - def self.to_readable(date) - date.strftime("%A, %B #{date.day.ordinalize}") - end + def self.to_readable(date) + date.strftime("%A, %B #{date.day.ordinalize}") + end - def self.full(date, timezone=nil) - return '' if date.nil? + def self.full(date, timezone = nil) + return "" if date.nil? date = Chronic.parse(date) if date.is_a?(String) - date = date.in_time_zone(timezone) if timezone - date.strftime("%m/%-d/%Y %l:%M%P") - end + date = date.in_time_zone(timezone) if timezone + date.strftime("%m/%-d/%Y %l:%M%P") + end - def self.full_range(date1, date2, timezone=nil) + def self.full_range(date1, date2, timezone = nil) return full(date1, timezone) if date2.nil? return full(date2, timezone) if date1.nil? if simple(date1) == simple(date2) - return full(date1, timezone) + ' - ' + time(date2, timezone) + full(date1, timezone) + " - " + time(date2, timezone) else - return full(date1, timezone) + ' - ' + full(date2, timezone) + full(date1, timezone) + " - " + full(date2, timezone) end end - def self.simple(date, timezone=nil) - return '' if date.nil? - date = Chronic.parse(date) if date.is_a?(String) - date = date.in_time_zone(timezone) if timezone - date.strftime("%m/%d/%Y") - end + def self.simple(date, timezone = nil) + return "" if date.nil? + date = Chronic.parse(date) if date.is_a?(String) + date = date.in_time_zone(timezone) if timezone + date.strftime("%m/%d/%Y") + end - def self.time(datetime, timezone=nil) - return '' if datetime.nil? - datetime = Chronic.parse(datetime) if datetime.is_a?(String) + def self.time(datetime, timezone = nil) + return "" if datetime.nil? + datetime = Chronic.parse(datetime) if datetime.is_a?(String) datetime = datetime.in_time_zone(timezone) if timezone datetime.strftime("%l:%M%P") end - def self.us_timezones - #zones=ActiveSupport::TimeZone.us_zones - zones=ActiveSupport::TimeZone.all - names = zones.map(&:name) - vals = zones.map{|t| t.tzinfo.name} - return names.zip(vals).sort_by{|name, val| name} - end + def self.us_timezones + # zones=ActiveSupport::TimeZone.us_zones + zones = ActiveSupport::TimeZone.all + names = zones.map(&:name) + vals = zones.map { |t| t.tzinfo.name } + names.zip(vals).sort_by { |name, val| name } + end def self.parse_partial_str(str) return nil if str.nil? Time.new(*str.match(/(\d\d\d\d)-?(\d\d)?-?(\d\d)?/).to_a[1..-1].compact.map(&:to_i)) end - end diff --git a/app/legacy_lib/format/dedication.rb b/app/legacy_lib/format/dedication.rb index 29650c18a..7ad55f252 100644 --- a/app/legacy_lib/format/dedication.rb +++ b/app/legacy_lib/format/dedication.rb @@ -1,16 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'json' +require "json" module Format module Dedication - def self.from_json(json_text) begin hash = JSON.parse(json_text) rescue return json_text end - return "Donation made in #{hash['type'] || 'honor'} of #{hash['name']}. Note: #{hash['note']}" + "Donation made in #{hash["type"] || "honor"} of #{hash["name"]}. Note: #{hash["note"]}" end end end diff --git a/app/legacy_lib/format/geography.rb b/app/legacy_lib/format/geography.rb index da9f9e5d6..ea41731eb 100644 --- a/app/legacy_lib/format/geography.rb +++ b/app/legacy_lib/format/geography.rb @@ -1,305 +1,303 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Format::Geography + StateCodes = ["AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"] - StateCodes = [ 'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY' ] + StateMappings = { + "alabama" => "AL", + "alaska" => "AK", + "arizona" => "AZ", + "arkansas" => "AR", + "california" => "CA", + "colorado" => "CO", + "connecticut" => "CT", + "delaware" => "DE", + "district of columbia" => "DC", + "florida" => "FL", + "georgia" => "GA", + "hawaii" => "HI", + "idaho" => "ID", + "illinois" => "IL", + "indiana" => "IN", + "iowa" => "IA", + "kansas" => "KS", + "kentucky" => "KY", + "louisiana" => "LA", + "maine" => "ME", + "maryland" => "MD", + "massachusetts" => "MA", + "michigan" => "MI", + "minnesota" => "MN", + "mississippi" => "MS", + "missouri" => "MO", + "montana" => "MT", + "nebraska" => "NE", + "nevada" => "NV", + "new hampshire" => "NH", + "new jersey" => "NJ", + "new mexico" => "NM", + "new york" => "NY", + "north carolina" => "NC", + "north dakota" => "ND", + "ohio" => "OH", + "oklahoma" => "OK", + "oregon" => "OR", + "pennsylvania" => "PA", + "puerto rico" => "PR", + "rhode island" => "RI", + "south carolina" => "SC", + "south dakota" => "SD", + "tennessee" => "TN", + "texas" => "TX", + "utah" => "UT", + "vermont" => "VT", + "virginia" => "VA", + "washington" => "WA", + "west virginia" => "WV", + "wisconsin" => "WI", + "wyoming" => "WY" + } - StateMappings = { - 'alabama' => 'AL', - 'alaska' => 'AK', - 'arizona' => 'AZ', - 'arkansas' => 'AR', - 'california' => 'CA', - 'colorado' => 'CO', - 'connecticut' => 'CT', - 'delaware' => 'DE', - 'district of columbia' => 'DC', - 'florida' => 'FL', - 'georgia' => 'GA', - 'hawaii' => 'HI', - 'idaho' => 'ID', - 'illinois' => 'IL', - 'indiana' => 'IN', - 'iowa' => 'IA', - 'kansas' => 'KS', - 'kentucky' => 'KY', - 'louisiana' => 'LA', - 'maine' => 'ME', - 'maryland' => 'MD', - 'massachusetts' => 'MA', - 'michigan' => 'MI', - 'minnesota' => 'MN', - 'mississippi' => 'MS', - 'missouri' => 'MO', - 'montana' => 'MT', - 'nebraska' => 'NE', - 'nevada' => 'NV', - 'new hampshire' => 'NH', - 'new jersey' => 'NJ', - 'new mexico' => 'NM', - 'new york' => 'NY', - 'north carolina' => 'NC', - 'north dakota' => 'ND', - 'ohio' => 'OH', - 'oklahoma' => 'OK', - 'oregon' => 'OR', - 'pennsylvania' => 'PA', - 'puerto rico' => 'PR', - 'rhode island' => 'RI', - 'south carolina' => 'SC', - 'south dakota' => 'SD', - 'tennessee' => 'TN', - 'texas' => 'TX', - 'utah' => 'UT', - 'vermont' => 'VT', - 'virginia' => 'VA', - 'washington' => 'WA', - 'west virginia' => 'WV', - 'wisconsin' => 'WI', - 'wyoming' => 'WY' - } - -Countries = [ - "Afghanistan", - "Albania", - "Algeria", - "American Samoa", - "Andorra", - "Angola", - "Anguilla", - "Antarctica", - "Antigua and Barbuda", - "Argentina", - "Armenia", - "Aruba", - "Australia", - "Austria", - "Azerbaijan", - "Bahamas", - "Bahrain", - "Bangladesh", - "Barbados", - "Belarus", - "Belgium", - "Belize", - "Benin", - "Bermuda", - "Bhutan", - "Bolivia", - "Bosnia and Herzegovina", - "Botswana", - "Bouvet Island", - "Brazil", - "British Indian Ocean Territory", - "Brunei Darussalam", - "Bulgaria", - "Burkina Faso", - "Burundi", - "Cambodia", - "Cameroon", - "Canada", - "Cape Verde", - "Cayman Islands", - "Central African Republic", - "Chad", - "Chile", - "China", - "Christmas Island", - "Cocos (Keeling) Islands", - "Colombia", - "Comoros", - "Congo", - "Cook Islands", - "Costa Rica", - "Cote D'ivoire", - "Croatia", - "Cuba", - "Cyprus", - "Czech Republic", - "Denmark", - "Djibouti", - "Dominica", - "Dominican Republic", - "Ecuador", - "Egypt", - "El Salvador", - "Equatorial Guinea", - "Eritrea", - "Estonia", - "Ethiopia", - "Falkland Islands (Malvinas)", - "Faroe Islands", - "Fiji", - "Finland", - "France", - "French Guiana", - "French Polynesia", - "French Southern Territories", - "Gabon", - "Gambia", - "Georgia", - "Germany", - "Ghana", - "Gibraltar", - "Greece", - "Greenland", - "Grenada", - "Guadeloupe", - "Guam", - "Guatemala", - "Guinea", - "Guinea-bissau", - "Guyana", - "Haiti", - "Heard Island and Mcdonald Islands", - "Honduras", - "Hong Kong", - "Hungary", - "Iceland", - "India", - "Indonesia", - "Iran", - "Iraq", - "Ireland", - "Israel", - "Italy", - "Jamaica", - "Japan", - "Jordan", - "Kazakhstan", - "Kenya", - "Kiribati", - "Korea (South)", - "Kuwait", - "Kyrgyzstan", - "Lao People's Democratic Republic", - "Latvia", - "Lebanon", - "Lesotho", - "Liberia", - "Libyan Arab Jamahiriya", - "Liechtenstein", - "Lithuania", - "Luxembourg", - "Macao", - "Macedonia", - "Madagascar", - "Malawi", - "Malaysia", - "Maldives", - "Mali", - "Malta", - "Marshall Islands", - "Martinique", - "Mauritania", - "Mauritius", - "Mayotte", - "Mexico", - "Micronesia", - "Moldova", - "Monaco", - "Mongolia", - "Montserrat", - "Morocco", - "Mozambique", - "Myanmar", - "Namibia", - "Nauru", - "Nepal", - "Netherlands", - "Netherlands Antilles", - "New Caledonia", - "New Zealand", - "Nicaragua", - "Niger", - "Nigeria", - "Niue", - "Norfolk Island", - "Northern Mariana Islands", - "Norway", - "Oman", - "Pakistan", - "Palau", - "Palestinian Territory", - "Panama", - "Papua New Guinea", - "Paraguay", - "Peru", - "Philippines", - "Pitcairn", - "Poland", - "Portugal", - "Puerto Rico", - "Qatar", - "Reunion", - "Romania", - "Russia", - "Rwanda", - "Saint Helena", - "Saint Kitts and Nevis", - "Saint Lucia", - "Saint Pierre and Miquelon", - "Saint Vincent and The Grenadines", - "Samoa", - "San Marino", - "Sao Tome and Principe", - "Saudi Arabia", - "Senegal", - "Serbia and Montenegro", - "Seychelles", - "Sierra Leone", - "Singapore", - "Slovakia", - "Slovenia", - "Solomon Islands", - "Somalia", - "South Africa", - "South Georgia and The South Sandwich Islands", - "Spain", - "Sri Lanka", - "Sudan", - "Suriname", - "Svalbard and Jan Mayen", - "Swaziland", - "Sweden", - "Switzerland", - "Syria ", - "Taiwan", - "Tajikistan", - "Tanzania", - "Thailand", - "Timor-leste", - "Togo", - "Tokelau", - "Tonga", - "Trinidad and Tobago", - "Tunisia", - "Turkey", - "Turkmenistan", - "Tuvalu", - "Uganda", - "Ukraine", - "United Arab Emirates", - "United Kingdom", - "United States", - "Uruguay", - "Uzbekistan", - "Vanuatu", - "Venezuela", - "Viet Nam", - "Virgin Islands", - "Wallis and Futuna", - "Western Sahara", - "Yemen", - "Zambia", - "Zimbabwe" -] - - # Convert a full state name like "New Mexico" into a code like "NM" - # Will leave strings that are already state codes alone - def self.full_state_to_code(str) - str = str.strip - return str if StateCodes.include?(str.upcase) - return StateMappings[str.downcase] - end + Countries = [ + "Afghanistan", + "Albania", + "Algeria", + "American Samoa", + "Andorra", + "Angola", + "Anguilla", + "Antarctica", + "Antigua and Barbuda", + "Argentina", + "Armenia", + "Aruba", + "Australia", + "Austria", + "Azerbaijan", + "Bahamas", + "Bahrain", + "Bangladesh", + "Barbados", + "Belarus", + "Belgium", + "Belize", + "Benin", + "Bermuda", + "Bhutan", + "Bolivia", + "Bosnia and Herzegovina", + "Botswana", + "Bouvet Island", + "Brazil", + "British Indian Ocean Territory", + "Brunei Darussalam", + "Bulgaria", + "Burkina Faso", + "Burundi", + "Cambodia", + "Cameroon", + "Canada", + "Cape Verde", + "Cayman Islands", + "Central African Republic", + "Chad", + "Chile", + "China", + "Christmas Island", + "Cocos (Keeling) Islands", + "Colombia", + "Comoros", + "Congo", + "Cook Islands", + "Costa Rica", + "Cote D'ivoire", + "Croatia", + "Cuba", + "Cyprus", + "Czech Republic", + "Denmark", + "Djibouti", + "Dominica", + "Dominican Republic", + "Ecuador", + "Egypt", + "El Salvador", + "Equatorial Guinea", + "Eritrea", + "Estonia", + "Ethiopia", + "Falkland Islands (Malvinas)", + "Faroe Islands", + "Fiji", + "Finland", + "France", + "French Guiana", + "French Polynesia", + "French Southern Territories", + "Gabon", + "Gambia", + "Georgia", + "Germany", + "Ghana", + "Gibraltar", + "Greece", + "Greenland", + "Grenada", + "Guadeloupe", + "Guam", + "Guatemala", + "Guinea", + "Guinea-bissau", + "Guyana", + "Haiti", + "Heard Island and Mcdonald Islands", + "Honduras", + "Hong Kong", + "Hungary", + "Iceland", + "India", + "Indonesia", + "Iran", + "Iraq", + "Ireland", + "Israel", + "Italy", + "Jamaica", + "Japan", + "Jordan", + "Kazakhstan", + "Kenya", + "Kiribati", + "Korea (South)", + "Kuwait", + "Kyrgyzstan", + "Lao People's Democratic Republic", + "Latvia", + "Lebanon", + "Lesotho", + "Liberia", + "Libyan Arab Jamahiriya", + "Liechtenstein", + "Lithuania", + "Luxembourg", + "Macao", + "Macedonia", + "Madagascar", + "Malawi", + "Malaysia", + "Maldives", + "Mali", + "Malta", + "Marshall Islands", + "Martinique", + "Mauritania", + "Mauritius", + "Mayotte", + "Mexico", + "Micronesia", + "Moldova", + "Monaco", + "Mongolia", + "Montserrat", + "Morocco", + "Mozambique", + "Myanmar", + "Namibia", + "Nauru", + "Nepal", + "Netherlands", + "Netherlands Antilles", + "New Caledonia", + "New Zealand", + "Nicaragua", + "Niger", + "Nigeria", + "Niue", + "Norfolk Island", + "Northern Mariana Islands", + "Norway", + "Oman", + "Pakistan", + "Palau", + "Palestinian Territory", + "Panama", + "Papua New Guinea", + "Paraguay", + "Peru", + "Philippines", + "Pitcairn", + "Poland", + "Portugal", + "Puerto Rico", + "Qatar", + "Reunion", + "Romania", + "Russia", + "Rwanda", + "Saint Helena", + "Saint Kitts and Nevis", + "Saint Lucia", + "Saint Pierre and Miquelon", + "Saint Vincent and The Grenadines", + "Samoa", + "San Marino", + "Sao Tome and Principe", + "Saudi Arabia", + "Senegal", + "Serbia and Montenegro", + "Seychelles", + "Sierra Leone", + "Singapore", + "Slovakia", + "Slovenia", + "Solomon Islands", + "Somalia", + "South Africa", + "South Georgia and The South Sandwich Islands", + "Spain", + "Sri Lanka", + "Sudan", + "Suriname", + "Svalbard and Jan Mayen", + "Swaziland", + "Sweden", + "Switzerland", + "Syria ", + "Taiwan", + "Tajikistan", + "Tanzania", + "Thailand", + "Timor-leste", + "Togo", + "Tokelau", + "Tonga", + "Trinidad and Tobago", + "Tunisia", + "Turkey", + "Turkmenistan", + "Tuvalu", + "Uganda", + "Ukraine", + "United Arab Emirates", + "United Kingdom", + "United States", + "Uruguay", + "Uzbekistan", + "Vanuatu", + "Venezuela", + "Viet Nam", + "Virgin Islands", + "Wallis and Futuna", + "Western Sahara", + "Yemen", + "Zambia", + "Zimbabwe" + ] + # Convert a full state name like "New Mexico" into a code like "NM" + # Will leave strings that are already state codes alone + def self.full_state_to_code(str) + str = str.strip + return str if StateCodes.include?(str.upcase) + StateMappings[str.downcase] + end end diff --git a/app/legacy_lib/format/html.rb b/app/legacy_lib/format/html.rb index 23f2a5433..cbccf9c26 100644 --- a/app/legacy_lib/format/html.rb +++ b/app/legacy_lib/format/html.rb @@ -2,7 +2,7 @@ module Format module HTML def self.has_only_empty_tags(html_str) - return true if html_str && html_str.gsub(/<[^>]*>/ui,'').gsub(" ", "").strip == "" + true if html_str && html_str.gsub(/<[^>]*>/ui, "").gsub(" ", "").strip == "" end end end diff --git a/app/legacy_lib/format/indefinitize.rb b/app/legacy_lib/format/indefinitize.rb index 68683734b..9f837ff56 100644 --- a/app/legacy_lib/format/indefinitize.rb +++ b/app/legacy_lib/format/indefinitize.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Format - module Indefinitize - VOWELS = %w(a e i o u) + module Indefinitize + VOWELS = %w[a e i o u] - def self.article word - VOWELS.include?(word[0].downcase) ? 'an' : 'a' - end + def self.article word + VOWELS.include?(word[0].downcase) ? "an" : "a" + end - def self.with_article word - article(word) + ' ' + word - end - end + def self.with_article word + article(word) + " " + word + end + end end diff --git a/app/legacy_lib/format/interpolate.rb b/app/legacy_lib/format/interpolate.rb index dc53a5a70..6457e55a2 100644 --- a/app/legacy_lib/format/interpolate.rb +++ b/app/legacy_lib/format/interpolate.rb @@ -2,8 +2,8 @@ module Format module Interpolate def self.with_hash(str, hash) - return '' if str.nil? - str.gsub(/{{.+}}/){|key| hash[key.gsub(/[{}]/,'')]} + return "" if str.nil? + str.gsub(/{{.+}}/) { |key| hash[key.gsub(/[{}]/, "")] } end end end diff --git a/app/legacy_lib/format/name.rb b/app/legacy_lib/format/name.rb index 53d4dccb1..7fcafdbab 100644 --- a/app/legacy_lib/format/name.rb +++ b/app/legacy_lib/format/name.rb @@ -1,17 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'active_support/core_ext' +require "active_support/core_ext" module Format - module Name - - def self.split_full(name) - return '' if name.nil? - name.split(/\ (\w+\s*)$/) - end + module Name + def self.split_full(name) + return "" if name.nil? + name.split(/\ (\w+\s*)$/) + end # Format a nonprofit name into an email header def self.email_from_np(np_name) - "\"#{np_name.gsub(',', '').gsub("\"", '')}\" <#{Settings.mailer.email}>" + "\"#{np_name.delete(",").delete("\"")}\" <#{Settings.mailer.email}>" end - end + end end diff --git a/app/legacy_lib/format/phone.rb b/app/legacy_lib/format/phone.rb index 6a3ed431c..57bc6e315 100644 --- a/app/legacy_lib/format/phone.rb +++ b/app/legacy_lib/format/phone.rb @@ -1,22 +1,19 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Format::Phone - - def self.readable(number) - # Convert to: - # (505) 263-6320 - # or: - # 263-6320 - return '' if number.blank? - - stripped = number.gsub(/[-\(\)\.\s]/, '') # remove extra chars and space - if stripped.length == 10 - return "(#{stripped[0..2]}) #{stripped[3..5]}-#{stripped[6..9]}" - elsif stripped.length == 7 - return "#{stripped[0..2]}-#{stripped[3..6]}" - else - return number - end - end + def self.readable(number) + # Convert to: + # (505) 263-6320 + # or: + # 263-6320 + return "" if number.blank? + stripped = number.gsub(/[-\(\)\.\s]/, "") # remove extra chars and space + if stripped.length == 10 + "(#{stripped[0..2]}) #{stripped[3..5]}-#{stripped[6..9]}" + elsif stripped.length == 7 + "#{stripped[0..2]}-#{stripped[3..6]}" + else + number + end + end end - diff --git a/app/legacy_lib/format/remove_diacritics.rb b/app/legacy_lib/format/remove_diacritics.rb index 52680e0c5..4d9459648 100644 --- a/app/legacy_lib/format/remove_diacritics.rb +++ b/app/legacy_lib/format/remove_diacritics.rb @@ -2,15 +2,12 @@ require "i18n" module Format - module RemoveDiacritics - - def self.from_hash(hash, keys) - # returns a new hash with any diacritics replaced with a plain character + module RemoveDiacritics + def self.from_hash(hash, keys) + # returns a new hash with any diacritics replaced with a plain character # only from values corresponding to specified keys: - # {"city" => "São Paulo"} ["city"] will return {"city" => "Sao Paulo"} - Hash[hash.map{|k, v| [k, (keys.include? k) ? I18n.transliterate(v) : v]}] - end - - end + # {"city" => "São Paulo"} ["city"] will return {"city" => "Sao Paulo"} + Hash[hash.map { |k, v| [k, keys.include?(k) ? I18n.transliterate(v) : v] }] + end + end end - diff --git a/app/legacy_lib/format/timezone.rb b/app/legacy_lib/format/timezone.rb index 08cec6dc7..7d315d5a0 100644 --- a/app/legacy_lib/format/timezone.rb +++ b/app/legacy_lib/format/timezone.rb @@ -2,24 +2,23 @@ module Format module Timezone def self.to_proxy(str) - dict = { - "Hawaii" => 'Pacific/Honolulu', - "Alaska" => 'America/Juneau', - "Pacific Time (US & Canada)" => 'America/Los_Angeles', - "Arizona" => 'America/Phoenix', - "Mountain Time (US & Canada)" => 'America/Denver', - "Central Time (US & Canada)" => 'America/Chicago', - "Eastern Time (US & Canada)" => 'America/New_York', - "Indiana (East)" => 'America/Indiana/Indianapolis' + dict = { + "Hawaii" => "Pacific/Honolulu", + "Alaska" => "America/Juneau", + "Pacific Time (US & Canada)" => "America/Los_Angeles", + "Arizona" => "America/Phoenix", + "Mountain Time (US & Canada)" => "America/Denver", + "Central Time (US & Canada)" => "America/Chicago", + "Eastern Time (US & Canada)" => "America/New_York", + "Indiana (East)" => "America/Indiana/Indianapolis" } if dict.has_key?(str) - return dict[str] + dict[str] elsif dict.has_value?(str) - return str + str else - return false + false end end end end - diff --git a/app/legacy_lib/format/url.rb b/app/legacy_lib/format/url.rb index 51de7c4b6..539282f78 100644 --- a/app/legacy_lib/format/url.rb +++ b/app/legacy_lib/format/url.rb @@ -1,23 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Format::Url + # Given ["What hello", "hi! lol?"] + # Return ["what-hello", "hi-lol"] + def self.convert_to_slug(*words) + return "" if words.empty? || !words.all? # true if any are nil or empty + words.map do |d| + d.strip.downcase + .gsub(/['`]/, "") # no apostrophes + .delete(".") # no dots + .gsub(/\s*@\s*/, " at ") # @ -> at + .gsub(/\s*&\s*/, " and ") # & -> and + .gsub(/\s*[^A-Za-z0-9\.\-]\s*/, "-") # replace oddballs with hyphen + .gsub(/\A[-\.]+|[-\.]+\z/, "") # strip leading/trailing hyphens + end.join("/") + end - # Given ["What hello", "hi! lol?"] - # Return ["what-hello", "hi-lol"] - def self.convert_to_slug(*words) - return '' if words.empty? || !words.all? # true if any are nil or empty - words.map do |d| - d.strip.downcase - .gsub(/['`]/,'') # no apostrophes - .gsub(/\./,'') # no dots - .gsub(/\s*@\s*/, ' at ') # @ -> at - .gsub(/\s*&\s*/, ' and ') # & -> and - .gsub(/\s*[^A-Za-z0-9\.\-]\s*/, '-') # replace oddballs with hyphen - .gsub(/\A[-\.]+|[-\.]+\z/,'') # strip leading/trailing hyphens - end.join("/") - end - - def self.concat(*urls) - return urls.join('/').gsub(/([^:])\/\/+/,'\1/') - end - + def self.concat(*urls) + urls.join("/").gsub(/([^:])\/\/+/, '\1/') + end end diff --git a/app/legacy_lib/geocode_model.rb b/app/legacy_lib/geocode_model.rb index cf802e549..17c990248 100644 --- a/app/legacy_lib/geocode_model.rb +++ b/app/legacy_lib/geocode_model.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module GeocodeModel - def self.supporter(id) supp = Supporter.find_by_id(id) if supp.address && supp.state_code && supp.city @@ -8,40 +7,40 @@ def self.supporter(id) end end - # Just a wrapper around a model's geocode method for delaying with: - # GeocodeModel.delay.geocode(user) - def self.geocode(model) - begin - model.geocode - rescue Exception => e - puts e - end - model.save - model - end + # Just a wrapper around a model's geocode method for delaying with: + # GeocodeModel.delay.geocode(user) + def self.geocode(model) + begin + model.geocode + rescue Exception => e + puts e + end + model.save + model + end - def self.with_reverse(model) - begin - model.geocode - model.reverse_geocode - rescue Exception => e - puts e - end - model.save - model - end + def self.with_reverse(model) + begin + model.geocode + model.reverse_geocode + rescue Exception => e + puts e + end + model.save + model + end - # Geocode and get the timezone for a model - def self.with_timezone(model) - begin - geocode(model) - rescue Exception => e - puts e - end - return model unless model.latitude && model.longitude + # Geocode and get the timezone for a model + def self.with_timezone(model) + begin + geocode(model) + rescue Exception => e + puts e + end + return model unless model.latitude && model.longitude - model.timezone = NearestTimeZone.to(model.latitude, model.longitude) - model.save - model - end + model.timezone = NearestTimeZone.to(model.latitude, model.longitude) + model.save + model + end end diff --git a/app/legacy_lib/get_data.rb b/app/legacy_lib/get_data.rb index 295fc19f1..aeb514014 100644 --- a/app/legacy_lib/get_data.rb +++ b/app/legacy_lib/get_data.rb @@ -1,33 +1,31 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module GetData + def self.chain(obj, *methods) + methods.each do |m| + if m.is_a?(Array) + params = m[1..-1] + m = m[0] + end - def self.chain(obj, *methods) - methods.each do |m| - if m.is_a?(Array) - params = m[1..-1] - m = m[0] - end - - if obj != nil && obj.respond_to?(m) - obj = obj.send(m, *params) - elsif obj.respond_to?(:has_key?) && obj.has_key?(m) - obj = obj[m] - else - return nil - end - end - return obj - end + if !obj.nil? && obj.respond_to?(m) + obj = obj.send(m, *params) + elsif obj.respond_to?(:has_key?) && obj.has_key?(m) + obj = obj[m] + else + return nil + end + end + obj + end def self.hash(h, *keys) - keys.each do |k| - if h.has_key?(k) - h = h[k] - else - return nil - end - end - return h + keys.each do |k| + if h.has_key?(k) + h = h[k] + else + return nil + end + end + h end end - diff --git a/app/legacy_lib/health_report.rb b/app/legacy_lib/health_report.rb index 2971e77cf..41ad53861 100644 --- a/app/legacy_lib/health_report.rb +++ b/app/legacy_lib/health_report.rb @@ -1,8 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' -require 'format/csv' -require 'format/currency' - +require "qx" +require "format/csv" +require "format/currency" module HealthReport # Send an email report about what has happend on the servers and database in the last 24hrs, and how things are running @@ -23,16 +22,16 @@ def self.query_data # Info about disabled nonprofit accounts due to ident verification disabled_nps = Nonprofit.includes(:stripe_account) - .where('created_at > ?', 3.months.ago).select{|i| i.stripe_account.verification_status != :verified} - .map{|np| {id: np.id, name: np.name, stripe_account_id: np.stripe_account_id}} + .where("created_at > ?", 3.months.ago).select { |i| i.stripe_account.verification_status != :verified } + .map { |np| {id: np.id, name: np.name, stripe_account_id: np.stripe_account_id} } - return { - charges_count: charges['count'], - charges_sum: charges['sum'], - charges_fees: charges['fees'], + { + charges_count: charges["count"], + charges_sum: charges["sum"], + charges_fees: charges["fees"], recently_disabled_nps: disabled_nps, - active_rec_don_count: rec_dons['count'], - active_rec_don_amount: rec_dons['sum'] + active_rec_don_count: rec_dons["count"], + active_rec_don_amount: rec_dons["sum"] } end @@ -40,7 +39,7 @@ def self.query_data def self.format_data data disabled_nps = Format::Csv.from_data(data[:recently_disabled_nps]) - return %Q( + %( Transaction Metrics for the last 24hrs: Total count: #{data[:charges_count]} Total amount: $#{Format::Currency.cents_to_dollars(data[:charges_sum])} diff --git a/app/legacy_lib/houdini_error.rb b/app/legacy_lib/houdini_error.rb index c17615533..724dafee7 100644 --- a/app/legacy_lib/houdini_error.rb +++ b/app/legacy_lib/houdini_error.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class HoudiniError < RuntimeError -end \ No newline at end of file +end diff --git a/app/legacy_lib/httparty/logger/commitchange_logger.rb b/app/legacy_lib/httparty/logger/commitchange_logger.rb index 83ecb1423..bd15bb6e6 100644 --- a/app/legacy_lib/httparty/logger/commitchange_logger.rb +++ b/app/legacy_lib/httparty/logger/commitchange_logger.rb @@ -28,29 +28,29 @@ class CommitchangeLogger attr_accessor :level, :logger, :output_type def initialize(logger, level, output_type) - @logger = logger - @level = level.to_sym + @logger = logger + @level = level.to_sym @output_type = output_type @messages = [] end def format(request, response) - @request = request + @request = request @response = response log_request log_response - logger.public_send level, JSON::generate(@output) + logger.public_send level, JSON.generate(@output) end attr_reader :request, :response def output_hash @output ||= { - type: output_type, - request: {}, - response: {} + type: output_type, + request: {}, + response: {} } end @@ -74,12 +74,12 @@ def log_request end def log_url - http_method = request.http_method.name.split('::').last.upcase + request.http_method.name.split("::").last.upcase uri = if request.options[:base_uri] - request.options[:base_uri] + request.path.path - else - request.path.to_s - end + request.options[:base_uri] + request.path.path + else + request.path.to_s + end output_request[:url] = uri end @@ -126,4 +126,4 @@ def log_response_body end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/httparty/logger/full_contact_logger.rb b/app/legacy_lib/httparty/logger/full_contact_logger.rb index e532a705e..a7f3c7716 100644 --- a/app/legacy_lib/httparty/logger/full_contact_logger.rb +++ b/app/legacy_lib/httparty/logger/full_contact_logger.rb @@ -26,8 +26,8 @@ module HTTParty module Logger class FullContactLogger < CommitchangeLogger def initialize(logger, level) - super(logger, level, 'full_contact') + super(logger, level, "full_contact") end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/httparty/logger/mailchimp_logger.rb b/app/legacy_lib/httparty/logger/mailchimp_logger.rb index 7f75f1c99..a9e090308 100644 --- a/app/legacy_lib/httparty/logger/mailchimp_logger.rb +++ b/app/legacy_lib/httparty/logger/mailchimp_logger.rb @@ -26,8 +26,8 @@ module HTTParty module Logger class MailchimpLogger < ::HTTParty::Logger::CommitchangeLogger def initialize(logger, level) - super(logger, level, 'mailchimp') + super(logger, level, "mailchimp") end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/image.rb b/app/legacy_lib/image.rb index 9e7a8e657..8df83324a 100644 --- a/app/legacy_lib/image.rb +++ b/app/legacy_lib/image.rb @@ -1,19 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Image - AssetPath = "https://dmnsmycmdpaix.cloudfront.net/uploads" - DefaultProfileUrl = Settings.default.image.profile; - DefaultNonprofitUrl = Settings.default.image.nonprofit; - DefaultCampaignUrl = Settings.default.image.campaign; + DefaultProfileUrl = Settings.default.image.profile + DefaultNonprofitUrl = Settings.default.image.nonprofit + DefaultCampaignUrl = Settings.default.image.campaign - def self._url(resource_name, image_name, version='normal') - %Q( + def self._url(resource_name, image_name, version = "normal") + %( concat(#{Qexpr.quote AssetPath} , '/', #{Qexpr.quote resource_name} , '/', #{Qexpr.quote image_name} - , '/', #{resource_name + '.id'} - , '/', #{Qexpr.quote version}, '_', #{resource_name + '.' + image_name}) - ) + , '/', #{resource_name + ".id"} + , '/', #{Qexpr.quote version}, '_', #{resource_name + "." + image_name}) + ) end end diff --git a/app/legacy_lib/import_civicrm_payments.rb b/app/legacy_lib/import_civicrm_payments.rb index 71bac5ff1..e796c2a53 100644 --- a/app/legacy_lib/import_civicrm_payments.rb +++ b/app/legacy_lib/import_civicrm_payments.rb @@ -1,93 +1,83 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ImportCivicrmPayments - ## MINIMALLY TESTED!!! def self.import_from_csv(csv_body, nonprofit, field_of_supporter_id) - Qx.transaction do - CSV::Converters[:blank_to_nil] = lambda do |field| - field && field.empty? ? nil : field - end - - csv = CSV.new(csv_body, :headers => true, :converters => [ :blank_to_nil]) - contrib_records = csv.to_a.map {|row| row.to_hash } - pay_imp = PaymentImport.create(nonprofit: nonprofit) - - supporter_id_custom_field = CustomFieldMaster.where("nonprofit_id = ? AND name = ?", nonprofit.id, field_of_supporter_id).first - - unless supporter_id_custom_field - raise ParamValidation::ValidationError.new("There is no custom field for nonprofit #{nonprofit.id} and field named #{field_of_supporter_id}", {key: :field_of_supporter_id}) - end - - supporters_with_fields = Supporter.includes(:custom_field_joins).where("supporters.nonprofit_id = ? AND custom_field_joins.custom_field_master_id = ?", nonprofit.id, supporter_id_custom_field.id) - questionable_records = [] - contrib_records.each {|r| - - our_supporter = supporters_with_fields.where('custom_field_joins.value = ?', r[field_of_supporter_id].to_s).first - unless our_supporter - questionable_records.push(r) - next - end - - known_fields = ['Date Received', 'Total Amount', ] - - notes = "" - r.except(known_fields).keys.each{|k| - notes += "#{k}: #{r[k]}\n" - } - - - offsite = nil - if r['payment_instrument'] == 'Check' - offsite = {kind: 'check', check_number: r['Check Number']} + Qx.transaction do + CSV::Converters[:blank_to_nil] = lambda do |field| + (field && field.empty?) ? nil : field end - puts r['Date Received'] - date_received = nil + csv = CSV.new(csv_body, headers: true, converters: [:blank_to_nil]) + contrib_records = csv.to_a.map { |row| row.to_hash } + pay_imp = PaymentImport.create(nonprofit: nonprofit) + supporter_id_custom_field = CustomFieldMaster.where("nonprofit_id = ? AND name = ?", nonprofit.id, field_of_supporter_id).first - Time.use_zone('Pacific Time (US & Canada)') do - date_received = Time.zone.parse(r['Date Received']) - puts date_received + unless supporter_id_custom_field + raise ParamValidation::ValidationError.new("There is no custom field for nonprofit #{nonprofit.id} and field named #{field_of_supporter_id}", {key: :field_of_supporter_id}) end - - - - d = InsertDonation.offsite( - { - amount: Format::Currency.dollars_to_cents(r['Total Amount']), - nonprofit_id: nonprofit.id, - supporter_id: our_supporter.id, - comment: notes, - date: date_received.to_s, - offsite_payment: offsite - }.with_indifferent_access - ) - puts d - pay_imp.donations.push(Donation.find(d[:json]['donation']['id'])) - } - questionable_records - end + supporters_with_fields = Supporter.includes(:custom_field_joins).where("supporters.nonprofit_id = ? AND custom_field_joins.custom_field_master_id = ?", nonprofit.id, supporter_id_custom_field.id) + questionable_records = [] + contrib_records.each { |r| + our_supporter = supporters_with_fields.where("custom_field_joins.value = ?", r[field_of_supporter_id].to_s).first + unless our_supporter + questionable_records.push(r) + next + end + + known_fields = ["Date Received", "Total Amount"] + + notes = "" + r.except(known_fields).keys.each { |k| + notes += "#{k}: #{r[k]}\n" + } + + offsite = nil + if r["payment_instrument"] == "Check" + offsite = {kind: "check", check_number: r["Check Number"]} + end + + puts r["Date Received"] + date_received = nil + + Time.use_zone("Pacific Time (US & Canada)") do + date_received = Time.zone.parse(r["Date Received"]) + puts date_received + end + + d = InsertDonation.offsite( + { + amount: Format::Currency.dollars_to_cents(r["Total Amount"]), + nonprofit_id: nonprofit.id, + supporter_id: our_supporter.id, + comment: notes, + date: date_received.to_s, + offsite_payment: offsite + }.with_indifferent_access + ) + puts d + pay_imp.donations.push(Donation.find(d[:json]["donation"]["id"])) + } + questionable_records + end end def self.undo(import_id) Qx.transaction do - import = PaymentImport.find(import_id) - import.donations.each{|d| - - d.payments.each{|p| - p.destroy + import = PaymentImport.find(import_id) + import.donations.each { |d| + d.payments.each { |p| + p.destroy + } + if d.offsite_payment + d.offsite_payment.destroy + end + + d.destroy } - if d.offsite_payment - d.offsite_payment.destroy - end - - - d.destroy - - } - import.destroy + import.destroy end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/import_onecause_event_donations.rb b/app/legacy_lib/import_onecause_event_donations.rb index 17da1249b..9f7bf2df7 100644 --- a/app/legacy_lib/import_onecause_event_donations.rb +++ b/app/legacy_lib/import_onecause_event_donations.rb @@ -3,84 +3,74 @@ module ImportOnecauseEventDonations # # Import from a Onecause Event Donation export # - # @param [Event] event the event the donations happened at + # @param [Event] event the event the donations happened at # @param [TicketLevel] event the ticket level used for users who don't have a ticket # @param [Array] csv csv import file # def self.import(event, ticket_level, csv) Qx.transaction do np = event.nonprofit - - bidder_groups = csv.group_by {|a| a['Bidder #']} + + bidder_groups = csv.group_by { |a| a["Bidder #"] } bidder_groups.keys.each do |i| - payment_row,non_payment = bidder_groups[i].partition{|row| row['Action'] == 'Payment'} + payment_row, non_payment = bidder_groups[i].partition { |row| row["Action"] == "Payment" } - payment_row = payment_row.select {|i| i['Payment Status'] == 'Approved'}.first + payment_row = payment_row.select { |i| i["Payment Status"] == "Approved" }.first + + supporter_info_row = payment_row || non_payment.first + + supporter_name = supporter_info_row["First Name"] + " " + supporter_info_row["Last Name"] + supporter = winnow_to_supporter(event, np, supporter_name, supporter_info_row["Email"]) + + supporter ||= Supporter.find(InsertSupporter.create_or_update(np.id, { + name: supporter_name, + email: supporter_info_row["Email"], + city: supporter_info_row["City"], + state_code: supporter_info_row["State"], + zip_code: supporter_info_row["Zip"], + phone: supporter_info_row["Phone #"], + organization: supporter_info_row["Company"] + })["id"]) - if payment_row - supporter_info_row = payment_row - else - supporter_info_row = non_payment.first - end - - supporter_name = supporter_info_row['First Name'] + " " + supporter_info_row['Last Name'] - supporter = winnow_to_supporter(event, np, supporter_name, supporter_info_row['Email']) - - - unless supporter - supporter = Supporter.find(InsertSupporter.create_or_update(np.id, { - name: supporter_name, - email: supporter_info_row['Email'], - city: supporter_info_row['City'], - state_code: supporter_info_row['State'], - zip_code: supporter_info_row['Zip'], - phone: supporter_info_row['Phone #'], - organization: supporter_info_row['Company'] - })['id']) - end - ticket = winnow_tickets(event, supporter) - - unless ticket + + ticket = if ticket + ticket.attributes + else # we create new ticket - ticket = InsertTickets.create({ + InsertTickets.create({ tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], event_id: event.id, nonprofit_id: np.id, supporter_id: supporter.id - }, true)['tickets'][0] - else - ticket = ticket.attributes + }, true)["tickets"][0] end if payment_row # do offsite donation for the supporter - donation = InsertDonation.offsite({ - 'amount': payment_row['Payment Amount'].to_i * 100, - 'nonprofit_id': np.id, - 'supporter_id': supporter.id, - 'event_id': event.id, - 'offsite_payment': {} + InsertDonation.offsite({ + amount: payment_row["Payment Amount"].to_i * 100, + nonprofit_id: np.id, + supporter_id: supporter.id, + event_id: event.id, + offsite_payment: {} }.with_indifferent_access) end - - notes = create_notes(payment_row, non_payment) - - notes = ticket['note'] ? ticket['note'] + '\n' + notes : notes + + notes = ticket["note"] ? ticket["note"] + '\n' + notes : notes # edit the ticket.notes for the supporter - UpdateTickets.update({event_id: event.id, ticket_id: ticket['id'], note: notes}) + UpdateTickets.update({event_id: event.id, ticket_id: ticket["id"], note: notes}) end end end - - def self.winnow_to_supporter(event, np, name, email=nil) - if email - possible_supporters = np.supporters.not_deleted.where('email = ? ', email) + def self.winnow_to_supporter(event, np, name, email = nil) + possible_supporters = if email + np.supporters.not_deleted.where("email = ? ", email) else - possible_supporters = np.supporters.not_deleted.where('name = ?', name) + np.supporters.not_deleted.where("name = ?", name) end if possible_supporters.none? @@ -88,29 +78,28 @@ def self.winnow_to_supporter(event, np, name, email=nil) elsif possible_supporters.one? return possible_supporters.first end - - tickets_for_supporters = event.tickets.where('supporter_id IN (?)', possible_supporters.map{|i| i.id}) - + + tickets_for_supporters = event.tickets.where("supporter_id IN (?)", possible_supporters.map { |i| i.id }) + if tickets_for_supporters.none? - return possible_supporters.first + possible_supporters.first elsif tickets_for_supporters.one? - return tickets_for_supporters.first.supporter + tickets_for_supporters.first.supporter else - return Supporter.find(tickets_for_supporters.map{|i| i.supporter_id}.uniq.first) + Supporter.find(tickets_for_supporters.map { |i| i.supporter_id }.uniq.first) end - end def self.winnow_tickets(event, supporter) - return event.tickets.where('supporter_id = ?', supporter.id).first + event.tickets.where("supporter_id = ?", supporter.id).first end - def self.create_notes(p_row, np_rows) - bidder_num = np_rows.first['Bidder #'] - table_num = np_rows.first['Table #'] - user_def_1 = np_rows.first['User Defined 1'] - user_def_2 = np_rows.first['User Defined 2'] - notes = np_rows.first['Notes'] + def self.create_notes(p_row, np_rows) + bidder_num = np_rows.first["Bidder #"] + table_num = np_rows.first["Table #"] + user_def_1 = np_rows.first["User Defined 1"] + user_def_2 = np_rows.first["User Defined 2"] + notes = np_rows.first["Notes"] output = [] @@ -118,19 +107,16 @@ def self.create_notes(p_row, np_rows) output.push("Table #: #{table_num}") if table_num output.push("User Defined 1: #{user_def_1}") if user_def_1 output.push("User Defined 2: #{user_def_2}") if user_def_2 - - output.push('Payments:') + output.push("Payments:") np_rows.each do |row| - row_str = "Item ##{row['Item #']}, #{row['Item Name']} -- $#{row['Amount']}, Value: $#{row['Value'] || 0}, Item/Charge Type: #{row['Item/Charge Type']}" + row_str = "Item ##{row["Item #"]}, #{row["Item Name"]} -- $#{row["Amount"]}, Value: $#{row["Value"] || 0}, Item/Charge Type: #{row["Item/Charge Type"]}" output.push("- #{row_str}") end - output.push("Notes: #{notes}") if notes - return output.join("\n") + output.join("\n") end - -end \ No newline at end of file +end diff --git a/app/legacy_lib/include_asset.rb b/app/legacy_lib/include_asset.rb index cd10bdb35..d59cfd177 100644 --- a/app/legacy_lib/include_asset.rb +++ b/app/legacy_lib/include_asset.rb @@ -1,19 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module IncludeAsset - # These are custom asset include functions for use in views that cache-bust using the current git version def self.js(path) - %Q().html_safe + %().html_safe end def self.css(path) - %Q().html_safe + %().html_safe end -private - + private + def self.asset_version - ENV['ASSET_VERSION'] + ENV["ASSET_VERSION"] end end diff --git a/app/legacy_lib/insert_activities.rb b/app/legacy_lib/insert_activities.rb index a2c08359f..6b6cce178 100644 --- a/app/legacy_lib/insert_activities.rb +++ b/app/legacy_lib/insert_activities.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' -require 'active_support/core_ext' -require 'format/currency' -require 'format/date' +require "qx" +require "active_support/core_ext" +require "format/currency" +require "format/date" module InsertActivities - def self.insert_cols ["action_type", "public", "created_at", "updated_at", "supporter_id", "attachment_type", "attachment_id", "nonprofit_id", "date", "json_data", "kind"] end @@ -60,7 +59,7 @@ def self.insert_one_time_donations_expr .join(:donations, "donations.id=payments.donation_id") .where("payments.kind='Donation'") end - + def self.for_tickets(ticket_ids) insert_tickets_expr .and_where("tickets.id IN ($ids)", ids: ticket_ids) @@ -69,7 +68,7 @@ def self.for_tickets(ticket_ids) def self.insert_tickets_expr Qx.insert_into(:activities, insert_cols) - .select(defaults.concat([ + .select(defaults.concat([ "tickets.supporter_id", "'Ticket' AS attachment_type", "tickets.id AS attachment_id", @@ -115,7 +114,7 @@ def self.for_supporter_notes(ids) def self.insert_supporter_notes_expr Qx.insert_into(:activities, insert_cols.concat(["user_id"])) - .select(defaults.concat([ + .select(defaults.concat([ "supporter_notes.supporter_id", "'SupporterEmail' AS attachment_type", "supporter_notes.id AS attachment_id", @@ -138,7 +137,7 @@ def self.for_offsite_donations(payment_ids) def self.insert_offsite_donations_expr Qx.insert_into(:activities, insert_cols.concat(["user_id"])) - .select(defaults.concat([ + .select(defaults.concat([ "payments.supporter_id", "'Payment' AS attachment_type", "payments.id AS attachment_id", @@ -154,6 +153,4 @@ def self.insert_offsite_donations_expr .add_join(:donations, "payments.donation_id=donations.id") .add_left_join(:users, "users.id=offsite_payments.user_id") end - - end diff --git a/app/legacy_lib/insert_bank_account.rb b/app/legacy_lib/insert_bank_account.rb index 822315be1..1ac550360 100644 --- a/app/legacy_lib/insert_bank_account.rb +++ b/app/legacy_lib/insert_bank_account.rb @@ -1,63 +1,59 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertBankAccount - # @param [Nonprofit] nonprofit # # stripe_bank_account_token: data.stripe_resp.id, - #stripe_bank_account_id: data.stripe_resp.bank_account.id, - # name: data.stripe_resp.bank_account.bank_name + ' *' + data.stripe_resp.bank_account.last4, - # email: app.user.email + # stripe_bank_account_id: data.stripe_resp.bank_account.id, + # name: data.stripe_resp.bank_account.bank_name + ' *' + data.stripe_resp.bank_account.last4, + # email: app.user.email - def self.with_stripe(nonprofit, user, params={}) + def self.with_stripe(nonprofit, user, params = {}) ParamValidation.new({nonprofit: nonprofit, user: user}, { - :nonprofit => { - :required => true, - :is_a => Nonprofit - }, - :user => { - :required => true, - :is_a => User - } + nonprofit: { + required: true, + is_a: Nonprofit + }, + user: { + required: true, + is_a: User + } }) - ParamValidation.new(params|| {}, { - :stripe_bank_account_token => { - :required => true, - :not_blank => true - } + ParamValidation.new(params || {}, { + stripe_bank_account_token: { + required: true, + not_blank: true + } }) stripe_acct = Stripe::Account.retrieve(StripeAccountUtils.find_or_create(nonprofit.id)) nonprofit.reload - #this shouldn't be possible but we'll check any who - if (nonprofit.stripe_account_id.blank?) + # this shouldn't be possible but we'll check any who + if nonprofit.stripe_account_id.blank? raise ArgumentError.new "#{nonprofit.id} does not have a valid stripe_account_id associated with it" end Qx.transaction do - begin - ba = stripe_acct.external_accounts.create(external_account: params[:stripe_bank_account_token]) - ba.default_for_currency = true - ba.save - - BankAccount.where('nonprofit_id = ?', nonprofit.id).update_all(deleted: true) - - bank_account = BankAccount.create( - stripe_bank_account_id: ba.id, - stripe_bank_account_token: params[:stripe_bank_account_token], - confirmation_token: SecureRandom.uuid, - nonprofit: nonprofit, - name: params[:name] || "Bank #{SecureRandom.uuid}", - email: user.email, - pending_verification: true - ) - - NonprofitMailer.delay.new_bank_account_notification(bank_account) - bank_account - rescue Stripe::StripeError => error - params[:failure_message] = "Failed to connect the bank account: #{error.inspect}" - raise ArgumentError.new("Failed to connect the bank account: #{error.inspect}") - end + ba = stripe_acct.external_accounts.create(external_account: params[:stripe_bank_account_token]) + ba.default_for_currency = true + ba.save + + BankAccount.where("nonprofit_id = ?", nonprofit.id).update_all(deleted: true) + + bank_account = BankAccount.create( + stripe_bank_account_id: ba.id, + stripe_bank_account_token: params[:stripe_bank_account_token], + confirmation_token: SecureRandom.uuid, + nonprofit: nonprofit, + name: params[:name] || "Bank #{SecureRandom.uuid}", + email: user.email, + pending_verification: true + ) + + NonprofitMailer.delay.new_bank_account_notification(bank_account) + bank_account + rescue Stripe::StripeError => error + params[:failure_message] = "Failed to connect the bank account: #{error.inspect}" + raise ArgumentError.new("Failed to connect the bank account: #{error.inspect}") end - end -end \ No newline at end of file +end diff --git a/app/legacy_lib/insert_card.rb b/app/legacy_lib/insert_card.rb index 590bdff6a..5dc54119d 100644 --- a/app/legacy_lib/insert_card.rb +++ b/app/legacy_lib/insert_card.rb @@ -1,7 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertCard - - # Create a new card # If a stripe_customer_id is present, then update that customer's primary source; otherwise create a new customer # @param [ActiveSupport::HashWithIndifferentAccess] card_data card data @@ -16,28 +14,25 @@ module InsertCard # @param [String] stripe_account_id not clear what this should do. # @param [Integer] event_id id for events with when you want it associated with an event - # @param [User] current_user the user making the request. Used for validating that the current_user can make a long term token request - def self.with_stripe(card_data, stripe_account_id=nil, event_id=nil, current_user = nil) - + # @param [User] current_user the user making the request. Used for validating that the current_user can make a long term token request + def self.with_stripe(card_data, stripe_account_id = nil, event_id = nil, current_user = nil) begin ParamValidation.new(card_data.to_deprecated_h.merge({event_id: event_id}), { - holder_type: {required: true, included_in: ['Nonprofit', 'Supporter']}, - holder_id: {required: true}, - stripe_card_id: {not_blank: true, required: true}, - stripe_card_token: {not_blank: true, required: true}, - name: {not_blank: true, required: true}, - event_id: {is_reference: true} + holder_type: {required: true, included_in: ["Nonprofit", "Supporter"]}, + holder_id: {required: true}, + stripe_card_id: {not_blank: true, required: true}, + stripe_card_token: {not_blank: true, required: true}, + name: {not_blank: true, required: true}, + event_id: {is_reference: true} }) rescue ParamValidation::ValidationError => e return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity} end - - # validate that the user is with the correct nonprofit - card_data = card_data.slice(:holder_type, :holder_id, :stripe_card_id, :stripe_card_token, :name ) - holder_types = {'Nonprofit' => :nonprofit, 'Supporter' => :supporter} + card_data = card_data.slice(:holder_type, :holder_id, :stripe_card_id, :stripe_card_token, :name) + holder_types = {"Nonprofit" => :nonprofit, "Supporter" => :supporter} holder_type = holder_types[card_data[:holder_type]] holder = nil begin @@ -52,12 +47,12 @@ def self.with_stripe(card_data, stripe_account_id=nil, event_id=nil, current_use begin if holder_type == :supporter && event_id - event = Event.where('id = ?', event_id).first + event = Event.where("id = ?", event_id).first unless event raise ParamValidation::ValidationError.new("#{event_id} is not a valid event", {key: :event_id}) end - if (holder.nonprofit != event.nonprofit ) + if holder.nonprofit != event.nonprofit raise ParamValidation::ValidationError.new("Event #{event_id} is not for the same nonprofit as supporter #{holder.id}", {key: :event_id}) end @@ -69,15 +64,14 @@ def self.with_stripe(card_data, stripe_account_id=nil, event_id=nil, current_use return {json: {error: "You're not authorized to perform that action"}, status: :unauthorized} rescue => e return {json: {error: "Oops! There was an error: #{e.message}"}, status: :unprocessable_entity} - end stripe_account_hash = {} # stripe_account_id ? {stripe_account: stripe_account_id} : {} begin - if card_data[:stripe_customer_id] - stripe_customer = Stripe::Customer.retrieve(card_data[:stripe_customer_id], stripe_account_hash) + stripe_customer = if card_data[:stripe_customer_id] + Stripe::Customer.retrieve(card_data[:stripe_customer_id], stripe_account_hash) else - stripe_customer = Stripe::Customer.create(customer_data(holder, card_data), stripe_account_hash) + Stripe::Customer.create(customer_data(holder, card_data), stripe_account_hash) end stripe_customer.sources.create(source: card_data[:stripe_card_token]) @@ -92,11 +86,10 @@ def self.with_stripe(card_data, stripe_account_id=nil, event_id=nil, current_use source_token = nil begin Card.transaction { - - if (holder_type == :nonprofit) + if holder_type == :nonprofit # @type [Nonprofit] holder card = holder.create_active_card(card_data) - elsif (holder_type == :supporter) + elsif holder_type == :supporter # @type [Supporter] holder card = holder.cards.create(card_data) params = {} @@ -117,11 +110,10 @@ def self.with_stripe(card_data, stripe_account_id=nil, event_id=nil, current_use return {json: {error: "Oops! There was an error saving your card, and it did not complete. Please try again in a moment. Error: #{e}"}, status: :unprocessable_entity} end - return { status: :ok, json: card.attributes.to_deprecated_h.with_indifferent_access.merge(token: source_token) } + {status: :ok, json: card.attributes.to_deprecated_h.with_indifferent_access.merge(token: source_token)} end def self.customer_data(holder, card_data) - { email: holder['email'], metadata: { cardholders_name: card_data[:cardholders_name], holder_id: card_data[:holder_id], holder_type: card_data[:holder_type] } } + {email: holder["email"], metadata: {cardholders_name: card_data[:cardholders_name], holder_id: card_data[:holder_id], holder_type: card_data[:holder_type]}} end - end diff --git a/app/legacy_lib/insert_charge.rb b/app/legacy_lib/insert_charge.rb index cd05b9f0f..155f86391 100644 --- a/app/legacy_lib/insert_charge.rb +++ b/app/legacy_lib/insert_charge.rb @@ -6,214 +6,207 @@ # require 'get_data' # require 'active_support/core_ext' -require 'stripe_account' unless !Settings.payment_provider.stripe_connect +require "stripe_account" unless !Settings.payment_provider.stripe_connect module InsertCharge - # In data, pass in: amount, nonprofit_id, supporter_id, card_id, statement # Optionally pass in :metadata for stripe and donation_id to connect to donation? # @raise [ParamValidation::ValidationError] parameter validation occurred # @raise [Stripe::StripeError] the stripe account couldn't be accessed or created def self.with_stripe(data) - begin - ParamValidation.new(data || {}, { - :amount => { - :required => true, - :is_integer => true, - :min => 0 - }, - :nonprofit_id => { - :required => true, - :is_integer => true - }, - :supporter_id => { - :required => true, - :is_integer => true - }, - :card_id => { - :required => true, - :is_integer => true - }, - :statement => { - :required => true, - :not_blank => true - } - }) - - np = Nonprofit.where('id = ?', data[:nonprofit_id]).first - - unless np - raise ParamValidation::ValidationError.new("#{data[:nonprofit_id]} is not a valid Nonprofit", {:key => :nonprofit_id}) - end + ParamValidation.new(data || {}, { + amount: { + required: true, + is_integer: true, + min: 0 + }, + nonprofit_id: { + required: true, + is_integer: true + }, + supporter_id: { + required: true, + is_integer: true + }, + card_id: { + required: true, + is_integer: true + }, + statement: { + required: true, + not_blank: true + } + }) + + np = Nonprofit.where("id = ?", data[:nonprofit_id]).first + + unless np + raise ParamValidation::ValidationError.new("#{data[:nonprofit_id]} is not a valid Nonprofit", {key: :nonprofit_id}) + end - supporter = Supporter.where('id = ?', data[:supporter_id]).first + supporter = Supporter.where("id = ?", data[:supporter_id]).first - unless supporter - raise ParamValidation::ValidationError.new("#{data[:supporter_id]} is not a valid Supporter", {:key => :supporter_id}) - end + unless supporter + raise ParamValidation::ValidationError.new("#{data[:supporter_id]} is not a valid Supporter", {key: :supporter_id}) + end - card = Card.where('id = ?', data[:card_id]).first + card = Card.where("id = ?", data[:card_id]).first - unless card - raise ParamValidation::ValidationError.new("#{data[:card_id]} is not a valid card", {:key => :card_id}) - end + unless card + raise ParamValidation::ValidationError.new("#{data[:card_id]} is not a valid card", {key: :card_id}) + end - unless np == supporter.nonprofit - raise ParamValidation::ValidationError.new("#{data[:supporter_id]} does not belong to this nonprofit #{np.id}", {:key => :supporter_id}) - end + unless np == supporter.nonprofit + raise ParamValidation::ValidationError.new("#{data[:supporter_id]} does not belong to this nonprofit #{np.id}", {key: :supporter_id}) + end - unless card.holder == supporter - if (data[:old_donation]) - #these are not new donations so we let them fly (for now) - Airbrake.notify(ParamValidation::ValidationError.new("#{data[:card_id]} does not belong to this supporter #{supporter.id} as warning", {:key => :card_id})) - else - raise ParamValidation::ValidationError.new("#{data[:card_id]} does not belong to this supporter #{supporter.id}", {:key => :card_id}) - end + unless card.holder == supporter + if data[:old_donation] + # these are not new donations so we let them fly (for now) + Airbrake.notify(ParamValidation::ValidationError.new("#{data[:card_id]} does not belong to this supporter #{supporter.id} as warning", {key: :card_id})) + else + raise ParamValidation::ValidationError.new("#{data[:card_id]} does not belong to this supporter #{supporter.id}", {key: :card_id}) end + end - result = {} - # Catch errors thrown by the stripe gem so we can respond with a 422 with an error message rather than 500 - begin - stripe_customer_id = card.stripe_customer_id - stripe_account_id = StripeAccountUtils.find_or_create(data[:nonprofit_id]) - rescue => e - Airbrake.notify(e, other_data: data) - raise e - end - nonprofit_currency = Qx.select(:currency).from(:nonprofits).where("id=$id", id: data[:nonprofit_id]).execute.first['currency'] - - stripe_charge_data = { - customer: stripe_customer_id, - amount: data[:amount], - currency: nonprofit_currency, - description: data[:statement], - statement_descriptor_suffix: data[:statement][0..21].gsub(/[<>"']/,''), - metadata: data[:metadata] - } - - if Settings.payment_provider.stripe_connect - stripe_account_id = StripeAccountUtils.find_or_create(data[:nonprofit_id]) - - + result = {} + # Catch errors thrown by the stripe gem so we can respond with a 422 with an error message rather than 500 + begin + stripe_customer_id = card.stripe_customer_id + stripe_account_id = StripeAccountUtils.find_or_create(data[:nonprofit_id]) + rescue => e + Airbrake.notify(e, other_data: data) + raise e + end + nonprofit_currency = Qx.select(:currency).from(:nonprofits).where("id=$id", id: data[:nonprofit_id]).execute.first["currency"] + + stripe_charge_data = { + customer: stripe_customer_id, + amount: data[:amount], + currency: nonprofit_currency, + description: data[:statement], + statement_descriptor_suffix: data[:statement][0..21].gsub(/[<>"']/, ""), + metadata: data[:metadata] + } + + if Settings.payment_provider.stripe_connect + stripe_account_id = StripeAccountUtils.find_or_create(data[:nonprofit_id]) # For backwards compatibility, see if the customer exists in the primary or the connected account # If it's a legacy customer, charge to the primary account and transfer with .destination # Otherwise, charge directly to the connected account - begin - stripe_cust = Stripe::Customer.retrieve({id: stripe_customer_id, expand: ['default_source']}, {stripe_version: "2019-09-09"}) - transfer_data = {transfer_data: { destination: stripe_account_id}, on_behalf_of: stripe_account_id} - - # Get the percentage fee on the nonprofit's billing - fee = Nonprofit.find(data[:nonprofit_id]).calculate_fee(amount: data[:amount], source: stripe_cust.default_source) - - stripe_charge_data[:application_fee_amount]= fee - - params = [stripe_charge_data.merge(transfer_data), {stripe_version: "2019-09-09"}] - rescue => e - Airbrake.notify(e,other_data: {reason: 'a payment that should never happen'}) - raise e - end - else - fee=0 - stripe_charge_data[:source]=card['stripe_card_id'] - params = [stripe_charge_data, {}] - end - begin - stripe_charge = Stripe::Charge.create(*params) - rescue Stripe::CardError => e - failure_message = "There was an error with your card: #{e.json_body[:error][:message]}" - Airbrake.notify(e) - rescue Stripe::StripeError => e - failure_message = "We're sorry, but something went wrong. We've been notified about this issue." - Airbrake.notify(e) - end - + stripe_cust = Stripe::Customer.retrieve({id: stripe_customer_id, expand: ["default_source"]}, {stripe_version: "2019-09-09"}) + transfer_data = {transfer_data: {destination: stripe_account_id}, on_behalf_of: stripe_account_id} - charge = Charge.new + # Get the percentage fee on the nonprofit's billing + fee = Nonprofit.find(data[:nonprofit_id]).calculate_fee(amount: data[:amount], source: stripe_cust.default_source) - charge.amount = data[:amount] - charge.fee = fee + stripe_charge_data[:application_fee_amount] = fee - charge.stripe_charge_id = stripe_charge&.id - charge.failure_message = failure_message - charge.status = stripe_charge&.paid ? 'pending' : 'failed' - charge.card = card - charge.donation = Donation.where('id = ?', data[:donation_id]).first - charge.supporter = supporter - charge.nonprofit = np - charge.save! - result['charge'] = charge - - if stripe_charge && stripe_charge.status != 'failed' - payment = Payment.new - payment.gross_amount = data[:amount] - payment.fee_total = -fee - payment.net_amount = data[:amount] - fee - payment.towards = data[:towards] - payment.kind = data[:kind] - payment.donation = Donation.where('id = ?', data[:donation_id]).first - payment.nonprofit = np - payment.supporter = supporter - payment.refund_total = 0 - payment.date = data[:date] || result['charge'].created_at - payment.save! - - - misc = payment.misc_payment_info || payment.create_misc_payment_info - - misc.fee_covered = data[:fee_covered] - misc.save! - - result['payment'] = payment - - charge.payment = payment - charge.save! - result['charge'] = charge + params = [stripe_charge_data.merge(transfer_data), {stripe_version: "2019-09-09"}] + rescue => e + Airbrake.notify(e, other_data: {reason: "a payment that should never happen"}) + raise e end + else + fee = 0 + stripe_charge_data[:source] = card["stripe_card_id"] + params = [stripe_charge_data, {}] + end - return result - rescue => e + begin + stripe_charge = Stripe::Charge.create(*params) + rescue Stripe::CardError => e + failure_message = "There was an error with your card: #{e.json_body[:error][:message]}" + Airbrake.notify(e) + rescue Stripe::StripeError => e + failure_message = "We're sorry, but something went wrong. We've been notified about this issue." Airbrake.notify(e) - raise e end + + charge = Charge.new + + charge.amount = data[:amount] + charge.fee = fee + + charge.stripe_charge_id = stripe_charge&.id + charge.failure_message = failure_message + charge.status = stripe_charge&.paid ? "pending" : "failed" + charge.card = card + charge.donation = Donation.where("id = ?", data[:donation_id]).first + charge.supporter = supporter + charge.nonprofit = np + charge.save! + result["charge"] = charge + + if stripe_charge && stripe_charge.status != "failed" + payment = Payment.new + payment.gross_amount = data[:amount] + payment.fee_total = -fee + payment.net_amount = data[:amount] - fee + payment.towards = data[:towards] + payment.kind = data[:kind] + payment.donation = Donation.where("id = ?", data[:donation_id]).first + payment.nonprofit = np + payment.supporter = supporter + payment.refund_total = 0 + payment.date = data[:date] || result["charge"].created_at + payment.save! + + misc = payment.misc_payment_info || payment.create_misc_payment_info + + misc.fee_covered = data[:fee_covered] + misc.save! + + result["payment"] = payment + + charge.payment = payment + charge.save! + result["charge"] = charge + end + + result + rescue => e + Airbrake.notify(e) + raise e end def self.with_sepa(data) result = {} entities = RetrieveActiveRecordItems.retrieve_from_keys(data, DirectDebitDetail => :direct_debit_detail_id, Supporter => :supporter_id, Nonprofit => :nonprofit_id) - nonprofit_currency = entities[:nonprofit_id].currency + entities[:nonprofit_id].currency # TODO fee = 0 - #todo charge should be changed to SEPA charge + # todo charge should be changed to SEPA charge c = Charge.new c.direct_debit_detail = entities[:direct_debit_detail_id] c.amount = data[:amount] c.fee = fee - c.status = 'pending' + c.status = "pending" c.nonprofit = entities[:nonprofit_id] c.supporter = entities[:supporter_id] c.save! - result['charge'] = c + result["charge"] = c p = Payment.new - p.gross_amount= data[:amount] - p.fee_total= -fee - p.net_amount= data[:amount] - fee + p.gross_amount = data[:amount] + p.fee_total = -fee + p.net_amount = data[:amount] - fee p.towards = data[:towards] p.kind = data[:kind] p.nonprofit = entities[:nonprofit_id] p.supporter = entities[:supporter_id] p.refund_total = 0 - p.date = data[:date] || result['charge'].created_at + p.date = data[:date] || result["charge"].created_at p.save! - result['payment'] = p + result["payment"] = p c.payment = p c.save! diff --git a/app/legacy_lib/insert_custom_field_joins.rb b/app/legacy_lib/insert_custom_field_joins.rb index 097037d60..d70d4f23e 100644 --- a/app/legacy_lib/insert_custom_field_joins.rb +++ b/app/legacy_lib/insert_custom_field_joins.rb @@ -1,41 +1,39 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - module InsertCustomFieldJoins - # Bulk insert many field joins into many supporters # for every field name, find or create it for the nonprofit # field_data should be an array of arrays liks [['Company', 'Pixar'], # ['Shirt-size', 'Small']] def self.find_or_create(np_id, supporter_ids, field_data) ParamValidation.new({np_id: np_id, supporter_ids: supporter_ids, field_data: field_data}, - { - :np_id => { - :required => true, - :is_integer=> true + { + np_id: { + required: true, + is_integer: true }, - :supporter_ids => { - :required => true, - :is_array => true, - :min_length => 1 + supporter_ids: { + required: true, + is_array: true, + min_length: 1 }, - :field_data => { - :required => true, - :is_array => true, - :min_length => 1 + field_data: { + required: true, + is_array: true, + min_length: 1 } - }) + }) - #make sure the np exists + # make sure the np exists np = Nonprofit.where("id = ? ", np_id).first unless np - raise ParamValidation::ValidationError.new("#{np_id} is not a valid non-profit", {:key => :np_id}) + raise ParamValidation::ValidationError.new("#{np_id} is not a valid non-profit", {key: :np_id}) end - #make sure the supporters_ids exist - supporter_ids.each {|id| - unless np.supporters.where('id = ?', id).exists? - raise ParamValidation::ValidationError.new("#{id} is not a valid supporter for nonprofit #{np_id}", {:key => :supporter_ids}) + # make sure the supporters_ids exist + supporter_ids.each { |id| + unless np.supporters.where("id = ?", id).exists? + raise ParamValidation::ValidationError.new("#{id} is not a valid supporter for nonprofit #{np_id}", {key: :supporter_ids}) end } @@ -43,17 +41,14 @@ def self.find_or_create(np_id, supporter_ids, field_data) # get the custom_field_master_id for each field_data name cfm_id_to_value = field_data.map { |name, value| cfm = CustomFieldMaster.where("nonprofit_id = ? and name = ?", np_id, name).first - unless cfm - cfm = CustomFieldMaster.create!(:nonprofit => np, :name => name) - end - {:custom_field_master_id => cfm.id, :value => value} + cfm ||= CustomFieldMaster.create!(nonprofit: np, name: name) + {custom_field_master_id: cfm.id, value: value} } in_bulk(np_id, supporter_ids, cfm_id_to_value) end end - # Validation: *np_id is valid, corresponds to real nonprofit # # @@ -65,18 +60,18 @@ def self.find_or_create(np_id, supporter_ids, field_data) def self.in_bulk(np_id, supporter_ids, field_data) begin ParamValidation.new({ - np_id: np_id, - supporter_ids: supporter_ids, - field_data: field_data - }, { - np_id: {required: true, is_integer: true}, - supporter_ids: {required:true, is_array: true}, - field_data: { required: true, is_array: true} - # array_of_hashes: { - # selected: {required: true}, tag_master_id: {required: true, is_integer: true} - # } - - }) + np_id: np_id, + supporter_ids: supporter_ids, + field_data: field_data + }, { + np_id: {required: true, is_integer: true}, + supporter_ids: {required: true, is_array: true}, + field_data: {required: true, is_array: true} + # array_of_hashes: { + # selected: {required: true}, tag_master_id: {required: true, is_integer: true} + # } + + }) rescue ParamValidation::ValidationError => e return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity} end @@ -85,40 +80,39 @@ def self.in_bulk(np_id, supporter_ids, field_data) return {json: {error: "Nonprofit #{np_id} is not valid"}, status: :unprocessable_entity} unless Nonprofit.exists?(np_id) # verify that the supporters belong to the nonprofit - supporter_ids = Supporter.where('nonprofit_id = ? and id IN (?)', np_id, supporter_ids).pluck(:id) + supporter_ids = Supporter.where("nonprofit_id = ? and id IN (?)", np_id, supporter_ids).pluck(:id) unless supporter_ids.any? return {json: {inserted_count: 0, removed_count: 0}, status: :ok} end # filtering the tag_data to this nonprofit - valid_ids = CustomFieldMaster.where('nonprofit_id = ? and id IN (?)', np_id, field_data.map {|fd| fd[:custom_field_master_id] }).pluck(:id).to_a - filtered_field_data = field_data.select {|i| valid_ids.include? i[:custom_field_master_id ].to_i} + valid_ids = CustomFieldMaster.where("nonprofit_id = ? and id IN (?)", np_id, field_data.map { |fd| fd[:custom_field_master_id] }).pluck(:id).to_a + filtered_field_data = field_data.select { |i| valid_ids.include? i[:custom_field_master_id].to_i } # first, delete the items which should be removed - to_insert, to_remove = filtered_field_data.partition{|t| + to_insert, to_remove = filtered_field_data.partition { |t| !t[:value].blank? } deleted = [] if to_remove.any? deleted = Qx.delete_from(:custom_field_joins) - .where("supporter_id IN ($ids)", ids: supporter_ids) - .and_where("custom_field_master_id in ($fields)", fields: to_remove.map{|t| t[:custom_field_master_id]}) - .returning('*') - .execute + .where("supporter_id IN ($ids)", ids: supporter_ids) + .and_where("custom_field_master_id in ($fields)", fields: to_remove.map { |t| t[:custom_field_master_id] }) + .returning("*") + .execute end - # next add only the selected tag_joins if to_insert.any? - insert_data = supporter_ids.map{|id| to_insert.map{|cfm| {supporter_id: id, custom_field_master_id: cfm[:custom_field_master_id], value: cfm[:value]}}}.flatten + insert_data = supporter_ids.map { |id| to_insert.map { |cfm| {supporter_id: id, custom_field_master_id: cfm[:custom_field_master_id], value: cfm[:value]} } }.flatten cfj = Qx.insert_into(:custom_field_joins) - .values(insert_data) - .timestamps - .on_conflict() - .conflict_columns(:supporter_id, :custom_field_master_id).upsert(:custom_field_join_supporter_unique_idx) - .returning('*') - .execute + .values(insert_data) + .timestamps + .on_conflict + .conflict_columns(:supporter_id, :custom_field_master_id).upsert(:custom_field_join_supporter_unique_idx) + .returning("*") + .execute else cfj = [] end @@ -132,10 +126,8 @@ def self.in_bulk(np_id, supporter_ids, field_data) # activities = Psql.execute( Qexpr.new.insert(:activities, activity_data) ) # Sync mailchimp lists, if present - #Mailchimp.delay.sync_supporters_to_list_from_tag_joins(np_id, supporter_ids, tag_data) - - return {json: {inserted_count: cfj.count, removed_count: deleted.count }, status: :ok} + # Mailchimp.delay.sync_supporters_to_list_from_tag_joins(np_id, supporter_ids, tag_data) + {json: {inserted_count: cfj.count, removed_count: deleted.count}, status: :ok} end - end diff --git a/app/legacy_lib/insert_direct_debit_detail.rb b/app/legacy_lib/insert_direct_debit_detail.rb index cf3219a4b..dadd22d71 100644 --- a/app/legacy_lib/insert_direct_debit_detail.rb +++ b/app/legacy_lib/insert_direct_debit_detail.rb @@ -17,6 +17,6 @@ def self.execute(params) return {json: {error: "Oops! There was an error saving your direct debit details, and it did not complete. Please try again in a moment. Error: #{e}"}, status: :unprocessable_entity} end - return { status: :ok, json: direct_debit_detail } + {status: :ok, json: direct_debit_detail} end end diff --git a/app/legacy_lib/insert_donation.rb b/app/legacy_lib/insert_donation.rb index 157be3d30..fe1cb092c 100644 --- a/app/legacy_lib/insert_donation.rb +++ b/app/legacy_lib/insert_donation.rb @@ -1,13 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertDonation - - # Make a one-time donation (call InsertRecurringDonation.with_stripe to create a recurring donation) # In data, pass in: # amount, card_id, nonprofit_id, supporter_id # designation, dedication # recurring_donation if is recurring - def self.with_stripe(data, current_user=nil) + def self.with_stripe(data, current_user = nil) data = data.to_deprecated_h.with_indifferent_access ParamValidation.new(data, common_param_validations @@ -17,7 +15,7 @@ def self.with_stripe(data, current_user=nil) tokenizable = source_token.tokenizable QuerySourceToken.validate_source_token_type(source_token) - entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) + entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) entities = entities.merge(RetrieveActiveRecordItems.retrieve_from_keys(data, {Campaign => :campaign_id, Event => :event_id, Profile => :profile_id}, true)) @@ -28,54 +26,54 @@ def self.with_stripe(data, current_user=nil) raise ParamValidation::ValidationError.new("Supporter #{entities[:supporter_id].id} does not own card #{tokenizable.id}", key: :token) end - data['card_id'] = tokenizable.id + data["card_id"] = tokenizable.id result = {} data[:date] = Time.now data = amount_from_data(data) - data = data.except(:old_donation).except('old_donation') + data = data.except(:old_donation).except("old_donation") result = result.merge(insert_charge(data)) - if result['charge']['status'] == 'failed' - raise ChargeError.new(result['charge']['failure_message']) + if result["charge"]["status"] == "failed" + raise ChargeError.new(result["charge"]["failure_message"]) end # Create the donation record - result['donation'] = self.insert_donation(data, entities) - trx = entities[:supporter_id].transactions.build(amount: data['amount'], created: data['date']) + result["donation"] = insert_donation(data, entities) + trx = entities[:supporter_id].transactions.build(amount: data["amount"], created: data["date"]) update_donation_keys(result) - don = trx.donations.build(amount: result['donation'].amount, legacy_donation: result['donation']) - legacy_payment = Payment.find(result['payment']['id']) + don = trx.donations.build(amount: result["donation"].amount, legacy_donation: result["donation"]) + legacy_payment = Payment.find(result["payment"]["id"]) stripe_transaction_charge = SubtransactionPayment.new( legacy_payment: legacy_payment, paymentable: StripeTransactionCharge.new, created: legacy_payment.date ) stripe_t = trx.build_subtransaction( - subtransactable: StripeTransaction.new(amount: data['amount']), - subtransaction_payments:[ + subtransactable: StripeTransaction.new(amount: data["amount"]), + subtransaction_payments: [ stripe_transaction_charge ] - ); + ) trx.save! don.save! stripe_t.save! stripe_t.subtransaction_payments.each(&:publish_created) - #stripe_t.publish_created + # stripe_t.publish_created don.publish_created trx.publish_created - result['activity'] = InsertActivities.for_one_time_donations([result['payment'].id]) - JobQueue.queue(JobTypes::DonationPaymentCreateJob, result['donation'].id, result['payment'].id, entities[:supporter_id].locale) + result["activity"] = InsertActivities.for_one_time_donations([result["payment"].id]) + JobQueue.queue(JobTypes::DonationPaymentCreateJob, result["donation"].id, result["payment"].id, entities[:supporter_id].locale) result end # Update the charge to have the payment and donation id # Update the payment to have the donation id def self.update_donation_keys(result) - result['charge'].donation = result['donation'] - result['charge'].save! + result["charge"].donation = result["donation"] + result["charge"].save! - result['payment'].donation = result['donation'] - result['payment'].save! + result["payment"].donation = result["donation"] + result["payment"].save! end # Insert a donation made from an offsite payment @@ -90,35 +88,35 @@ def self.offsite(data) validate_all_entities(entities) data = amount_from_data(date_from_data(data)) - result = {'donation' => self.insert_donation(data.except('offsite_payment'), entities)} - trx = entities[:supporter_id].transactions.build(amount: data['amount'], created: data['date']) - don = trx.donations.build(amount: result['donation'].amount, legacy_donation: result['donation']) - result['payment'] = self.insert_payment('OffsitePayment', 0, result['donation']['id'], data) - result['offsite_payment'] = Psql.execute( + result = {"donation" => insert_donation(data.except("offsite_payment"), entities)} + trx = entities[:supporter_id].transactions.build(amount: data["amount"], created: data["date"]) + don = trx.donations.build(amount: result["donation"].amount, legacy_donation: result["donation"]) + result["payment"] = insert_payment("OffsitePayment", 0, result["donation"]["id"], data) + result["offsite_payment"] = Psql.execute( Qexpr.new.insert(:offsite_payments, [ - (data['offsite_payment']&.to_deprecated_h&.with_indifferent_access || {}).merge({ - gross_amount: data['amount'], - nonprofit_id: data['nonprofit_id'], - supporter_id: data['supporter_id'], - donation_id: result['donation']['id'], - payment_id: result['payment']['id'], - date: data['date'] + (data["offsite_payment"]&.to_deprecated_h&.with_indifferent_access || {}).merge({ + gross_amount: data["amount"], + nonprofit_id: data["nonprofit_id"], + supporter_id: data["supporter_id"], + donation_id: result["donation"]["id"], + payment_id: result["payment"]["id"], + date: data["date"] }) - ]).returning('*') + ]).returning("*") ).first - legacy_payment = Payment.find(result['payment']['id']) + legacy_payment = Payment.find(result["payment"]["id"]) offline_transaction_charge_payment = SubtransactionPayment.new( - legacy_payment: legacy_payment, - paymentable: OfflineTransactionCharge.new, - created: legacy_payment.date - ) + legacy_payment: legacy_payment, + paymentable: OfflineTransactionCharge.new, + created: legacy_payment.date + ) off_t = trx.build_subtransaction( - subtransactable: OfflineTransaction.new(amount: data['amount']), - subtransaction_payments:[ + subtransactable: OfflineTransaction.new(amount: data["amount"]), + subtransaction_payments: [ offline_transaction_charge_payment - ], - created: data['date'] - ); + ], + created: data["date"] + ) trx.save! don.save! off_t.save! @@ -128,9 +126,9 @@ def self.offsite(data) # off_t.publish_created offline_transaction_charge_payment.publish_created - result['activity'] = InsertActivities.for_offsite_donations([result['payment']['id']]) - - return {status: 200, json: result} + result["activity"] = InsertActivities.for_offsite_donations([result["payment"]["id"]]) + + {status: 200, json: result} end def self.with_sepa(data) @@ -138,7 +136,7 @@ def self.with_sepa(data) ParamValidation.new(data, common_param_validations .merge(direct_debit_detail_id: {required: true, is_reference: true})) - entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) + entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) entities = entities.merge(RetrieveActiveRecordItems.retrieve_from_keys(data, {Campaign => :campaign_id, Event => :event_id, Profile => :profile_id}, true)) @@ -146,17 +144,17 @@ def self.with_sepa(data) data[:date] = Time.now result = result.merge(insert_charge(data)) - result['donation'] = self.insert_donation(data, entities) + result["donation"] = insert_donation(data, entities) update_donation_keys(result) - JobQueue.queue(JobTypes::NonprofitPaymentNotificationJob, result['donation'].id, result['donation'].payment.id) - JobQueue.queue(JobTypes::DonorDirectDebitNotificationJob, result['donation'].id, result['donation'].supporter.locale) + JobQueue.queue(JobTypes::NonprofitPaymentNotificationJob, result["donation"].id, result["donation"].payment.id) + JobQueue.queue(JobTypes::DonorDirectDebitNotificationJob, result["donation"].id, result["donation"].supporter.locale) # do this for making test consistent - result['activity'] = {} + result["activity"] = {} result end -private + private def self.get_nonprofit_data(nonprofit_id) Nonprofit.find(nonprofit_id) @@ -164,33 +162,33 @@ def self.get_nonprofit_data(nonprofit_id) def self.insert_charge(data) payment_provider = payment_provider(data) - nonprofit_data = get_nonprofit_data(data['nonprofit_id']) - kind = data['recurring_donation'] ? "RecurringDonation" : "Donation" - if payment_provider == 'credit_card' - return InsertCharge.with_stripe({ - donation_id: data['donation_id'], + nonprofit_data = get_nonprofit_data(data["nonprofit_id"]) + kind = data["recurring_donation"] ? "RecurringDonation" : "Donation" + if payment_provider == "credit_card" + InsertCharge.with_stripe({ + donation_id: data["donation_id"], kind: kind, - towards: data['designation'], - metadata: {kind: kind, nonprofit_id: data['nonprofit_id']}, - statement: "Donation #{nonprofit_data['statement'] || nonprofit_data['name']}", - amount: data['amount'], - nonprofit_id: data['nonprofit_id'], - supporter_id: data['supporter_id'], - card_id: data['card_id'], - old_donation: data['old_donation'] ? true : false, - fee_covered: data['fee_covered'] + towards: data["designation"], + metadata: {kind: kind, nonprofit_id: data["nonprofit_id"]}, + statement: "Donation #{nonprofit_data["statement"] || nonprofit_data["name"]}", + amount: data["amount"], + nonprofit_id: data["nonprofit_id"], + supporter_id: data["supporter_id"], + card_id: data["card_id"], + old_donation: data["old_donation"] ? true : false, + fee_covered: data["fee_covered"] }) - elsif payment_provider == 'sepa' - return InsertCharge.with_sepa({ - donation_id: data['donation_id'], + elsif payment_provider == "sepa" + InsertCharge.with_sepa({ + donation_id: data["donation_id"], kind: kind, - towards: data['designation'], - metadata: {kind: kind, nonprofit_id: data['nonprofit_id']}, - statement: "Donation #{nonprofit_data['statement'] || nonprofit_data['name']}", - amount: data['amount'], - nonprofit_id: data['nonprofit_id'], - supporter_id: data['supporter_id'], - direct_debit_detail_id: data['direct_debit_detail_id'] + towards: data["designation"], + metadata: {kind: kind, nonprofit_id: data["nonprofit_id"]}, + statement: "Donation #{nonprofit_data["statement"] || nonprofit_data["name"]}", + amount: data["amount"], + nonprofit_id: data["nonprofit_id"], + supporter_id: data["supporter_id"], + direct_debit_detail_id: data["direct_debit_detail_id"] }) end end @@ -200,30 +198,30 @@ def self.insert_payment(kind, fee_total, donation_id, data) Psql.execute( Qexpr.new.insert(:payments, [{ donation_id: donation_id, - gross_amount: data['amount'], - nonprofit_id: data['nonprofit_id'], - supporter_id: data['supporter_id'], + gross_amount: data["amount"], + nonprofit_id: data["nonprofit_id"], + supporter_id: data["supporter_id"], refund_total: 0, - date: data['date'], - towards: data['designation'], + date: data["date"], + towards: data["designation"], kind: kind, fee_total: fee_total, - net_amount: data['amount'] - fee_total - }]).returning('*') + net_amount: data["amount"] - fee_total + }]).returning("*") ).first end # Insert a donation row def self.insert_donation(data, entities) d = Donation.new - d.date = data['date'] - d.anonymous = data['anonymous'] - d.designation = data['designation'] - d.dedication = data['dedication'] - d.comment = data['comment'] - d.amount = data['amount'] - d.card = Card.find(data['card_id']) if data['card_id'] - d.direct_debit_detail = DirectDebitDetail.find(data['direct_debit_detail_id']) if data['direct_debit_detail_id'] + d.date = data["date"] + d.anonymous = data["anonymous"] + d.designation = data["designation"] + d.dedication = data["dedication"] + d.comment = data["comment"] + d.amount = data["amount"] + d.card = Card.find(data["card_id"]) if data["card_id"] + d.direct_debit_detail = DirectDebitDetail.find(data["direct_debit_detail_id"]) if data["direct_debit_detail_id"] d.nonprofit = entities[:nonprofit_id] d.supporter = entities[:supporter_id] d.profile = entities[:profile_id] || nil @@ -236,34 +234,34 @@ def self.insert_donation(data, entities) # Return either the parsed DateTime from a date in data, or right now def self.date_from_data(data) - data.merge('date' => data['date'].blank? ? Time.current : Chronic.parse(data['date'])) + data.merge("date" => data["date"].blank? ? Time.current : Chronic.parse(data["date"])) end def self.amount_from_data(data) - data.merge('amount' => data['amount'].to_i) + data.merge("amount" => data["amount"].to_i) end def self.payment_provider(data) if data[:card_id] || data["card_id"] - 'credit_card' + "credit_card" elsif data[:direct_debit_detail_id] || data["direct_debit_detail_id"] - 'sepa' + "sepa" end end -def self.parse_date(date) + def self.parse_date(date) date.blank? ? Time.current : Chronic.parse(date) end def self.common_param_validations { - amount: {required: true, is_integer: true}, - nonprofit_id: {required: true, is_reference: true}, - supporter_id: {required: true, is_reference: true}, - designation: {is_a: String}, - dedication: {is_a: String}, - campaign_id: {is_reference: true}, - event_id: {is_reference: true}, + amount: {required: true, is_integer: true}, + nonprofit_id: {required: true, is_reference: true}, + supporter_id: {required: true, is_reference: true}, + designation: {is_a: String}, + dedication: {is_a: String}, + campaign_id: {is_reference: true}, + event_id: {is_reference: true} } end diff --git a/app/legacy_lib/insert_duplicate.rb b/app/legacy_lib/insert_duplicate.rb index 41d1c26ea..c0388af77 100644 --- a/app/legacy_lib/insert_duplicate.rb +++ b/app/legacy_lib/insert_duplicate.rb @@ -1,19 +1,19 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertDuplicate - def self.campaign(campaign_id, profile_id, new_nonprofit=nil) - ParamValidation.new({:campaign_id => campaign_id, :profile_id => profile_id}, - { - :campaign_id => {:required => true, :is_integer => true}, - :profile_id => {:required => true, :is_integer => true} - }) + def self.campaign(campaign_id, profile_id, new_nonprofit = nil) + ParamValidation.new({campaign_id: campaign_id, profile_id: profile_id}, + { + campaign_id: {required: true, is_integer: true}, + profile_id: {required: true, is_integer: true} + }) campaign = Campaign.where("id = ?", campaign_id).first unless campaign - raise ParamValidation::ValidationError.new("#{campaign_id} is not a valid campaign", {:key => :campaign_id}) + raise ParamValidation::ValidationError.new("#{campaign_id} is not a valid campaign", {key: :campaign_id}) end profile = Profile.where("id = ?", profile_id).first unless profile - raise ParamValidation::ValidationError.new("#{profile_id} is not a valid profile", {:key =>:profile_id}) + raise ParamValidation::ValidationError.new("#{profile_id} is not a valid profile", {key: :profile_id}) end Qx.transaction do @@ -21,7 +21,7 @@ def self.campaign(campaign_id, profile_id, new_nonprofit=nil) dupe.slug = SlugCopyNamingAlgorithm.new(Campaign, dupe.nonprofit.id).create_copy_name(dupe.slug) dupe.name = NameCopyNamingAlgorithm.new(Campaign, dupe.nonprofit.id).create_copy_name(dupe.name) - if (dupe.end_datetime && dupe.end_datetime.ago(7.days) < DateTime.now) + if dupe.end_datetime && dupe.end_datetime.ago(7.days) < DateTime.now dupe.end_datetime = DateTime.now.since(7.days) end @@ -31,9 +31,17 @@ def self.campaign(campaign_id, profile_id, new_nonprofit=nil) dupe.save! - dupe.update_attribute(:main_image, campaign.main_image) unless !campaign.main_image rescue Aws::S3::Errors::NoSuchKey + begin + dupe.update_attribute(:main_image, campaign.main_image) unless !campaign.main_image + rescue + Aws::S3::Errors::NoSuchKey + end - dupe.update_attribute(:background_image, campaign.background_image) unless !campaign.background_image rescue Aws::S3::Errors::NoSuchKey + begin + dupe.update_attribute(:background_image, campaign.background_image) unless !campaign.background_image + rescue + Aws::S3::Errors::NoSuchKey + end InsertDuplicate.campaign_gift_options(campaign_id, dupe.id) @@ -41,20 +49,20 @@ def self.campaign(campaign_id, profile_id, new_nonprofit=nil) end end - def self.event(event_id, profile_id, new_nonprofit=nil) - ParamValidation.new({:event_id => event_id, :profile_id => profile_id}, - { - :event_id => {:required => true, :is_integer => true}, - :profile_id => {:required => true, :is_integer => true} - }) + def self.event(event_id, profile_id, new_nonprofit = nil) + ParamValidation.new({event_id: event_id, profile_id: profile_id}, + { + event_id: {required: true, is_integer: true}, + profile_id: {required: true, is_integer: true} + }) event = Event.where("id = ?", event_id).first unless event - raise ParamValidation::ValidationError.new("#{event_id} is not a valid event", {:key => :event_id}) + raise ParamValidation::ValidationError.new("#{event_id} is not a valid event", {key: :event_id}) end profile = Profile.where("id = ?", profile_id).first unless profile - raise ParamValidation::ValidationError.new("#{profile_id} is not a valid profile", {:key =>:profile_id}) + raise ParamValidation::ValidationError.new("#{profile_id} is not a valid profile", {key: :profile_id}) end Qx.transaction do @@ -65,16 +73,16 @@ def self.event(event_id, profile_id, new_nonprofit=nil) we_changed_start_time = false - length_of_event = dupe.end_datetime - dupe.start_datetime - if (dupe.start_datetime.ago(7.days) < DateTime.now) + length_of_event = dupe.end_datetime - dupe.start_datetime + if dupe.start_datetime.ago(7.days) < DateTime.now dupe.start_datetime = DateTime.now.since(7.days) we_changed_start_time = true end - if (we_changed_start_time && dupe.end_datetime) + if we_changed_start_time && dupe.end_datetime dupe.end_datetime = dupe.start_datetime.since(length_of_event) end - + dupe.nonprofit = new_nonprofit if new_nonprofit dupe.organizer_email = profile.user.email dupe.profile = profile @@ -82,9 +90,17 @@ def self.event(event_id, profile_id, new_nonprofit=nil) dupe.save! - dupe.update_attribute(:main_image, event.main_image) unless !event.main_image rescue Aws::S3::Errors::NoSuchKey + begin + dupe.update_attribute(:main_image, event.main_image) unless !event.main_image + rescue + Aws::S3::Errors::NoSuchKey + end - dupe.update_attribute(:background_image, event.background_image) unless !event.background_image rescue Aws::S3::Errors::NoSuchKey + begin + dupe.update_attribute(:background_image, event.background_image) unless !event.background_image + rescue + Aws::S3::Errors::NoSuchKey + end InsertDuplicate.ticket_levels(event_id, dupe.id) InsertDuplicate.event_discounts(event_id, dupe.id) @@ -110,10 +126,10 @@ def self.campaign_gift_options(old_campaign_id, new_campaign_id) .from("campaign_gift_options") .where(campaign_id: old_campaign_id) .execute - .map {|c| c.except("id", "created_at", "updated_at", "campaign_id") } + .map { |c| c.except("id", "created_at", "updated_at", "campaign_id") } if cgos.any? - return Qx.insert_into("campaign_gift_options") + Qx.insert_into("campaign_gift_options") .values(cgos) .common_values({campaign_id: new_campaign_id}) .ts @@ -129,10 +145,10 @@ def self.ticket_levels(old_event_id, new_event_id) .from("ticket_levels") .where(event_id: old_event_id) .execute - .map {|t| t.except("id", "created_at", "updated_at", "event_id") } + .map { |t| t.except("id", "created_at", "updated_at", "event_id") } if tls.any? - return Qx.insert_into("ticket_levels") + Qx.insert_into("ticket_levels") .values(tls) .common_values({event_id: new_event_id}) .ts @@ -145,19 +161,18 @@ def self.ticket_levels(old_event_id, new_event_id) # and inserts them and creates associations with a new event def self.event_discounts(old_event_id, new_event_id) eds = Qx.select("*") - .from("event_discounts") - .where(event_id: old_event_id) - .execute - .map {|t| t.except("id", "created_at", "updated_at", "event_id") } + .from("event_discounts") + .where(event_id: old_event_id) + .execute + .map { |t| t.except("id", "created_at", "updated_at", "event_id") } if eds.any? - return Qx.insert_into("event_discounts") - .values(eds) - .common_values({event_id: new_event_id}) - .ts - .returning("*") - .execute + Qx.insert_into("event_discounts") + .values(eds) + .common_values({event_id: new_event_id}) + .ts + .returning("*") + .execute end end end - diff --git a/app/legacy_lib/insert_email_lists.rb b/app/legacy_lib/insert_email_lists.rb index c62ff66af..9714b386e 100644 --- a/app/legacy_lib/insert_email_lists.rb +++ b/app/legacy_lib/insert_email_lists.rb @@ -1,44 +1,41 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' +require "qx" module InsertEmailLists - def self.for_mailchimp(npo_id, tag_master_ids) # Partial SQL expression for deleting deselected tags - tags_for_nonprofit = Nonprofit.includes(:tag_masters => :email_list).find(npo_id).tag_masters.not_deleted; - tag_master_ids = tags_for_nonprofit.where('id in (?)', tag_master_ids).pluck(:id) + tags_for_nonprofit = Nonprofit.includes(tag_masters: :email_list).find(npo_id).tag_masters.not_deleted + tag_master_ids = tags_for_nonprofit.where("id in (?)", tag_master_ids).pluck(:id) if tag_master_ids.empty? # no tags were selected; remove all email lists - deleted = tags_for_nonprofit.includes(:email_list).where("email_lists.id IS NOT NULL").references(:email_lists).map{|i| i.email_list} - EmailList.where('id IN (?)', deleted.map{|i| i.id}).delete_all + deleted = tags_for_nonprofit.includes(:email_list).where.not(email_lists: {id: nil}).references(:email_lists).map { |i| i.email_list } + EmailList.where("id IN (?)", deleted.map { |i| i.id }).delete_all else # Remove all email lists that exist in the db that are not included in tag_master_ids - deleted = tags_for_nonprofit.includes(:email_list).where("email_lists.tag_master_id NOT IN (?)", tag_master_ids).references(:email_lists).map{|i| i.email_list} - EmailList.where('id IN (?)', deleted.map{|i| i.id}).delete_all + deleted = tags_for_nonprofit.includes(:email_list).where.not(email_lists: {tag_master_id: tag_master_ids}).references(:email_lists).map { |i| i.email_list } + EmailList.where("id IN (?)", deleted.map { |i| i.id }).delete_all end - mailchimp_lists_to_delete = deleted.map{|i| i.mailchimp_list_id} + mailchimp_lists_to_delete = deleted.map { |i| i.mailchimp_list_id } result = Mailchimp.delete_mailchimp_lists(npo_id, mailchimp_lists_to_delete) - return {deleted: deleted.map{|i| {'mailchimp_list_id' => i.mailchimp_list_id}}, deleted_result: result} if tag_master_ids.empty? + return {deleted: deleted.map { |i| {"mailchimp_list_id" => i.mailchimp_list_id} }, deleted_result: result} if tag_master_ids.empty? - existing = tags_for_nonprofit.includes(:email_list).where('email_lists.tag_master_id IN (?)', tag_master_ids).references(:email_lists) + existing = tags_for_nonprofit.includes(:email_list).where("email_lists.tag_master_id IN (?)", tag_master_ids).references(:email_lists) - tag_master_ids -= existing.map{|i| i.id} + tag_master_ids -= existing.map { |i| i.id } lists = Mailchimp.create_mailchimp_lists(npo_id, tag_master_ids) if !lists || !lists.any? || !lists.first[:name] - raise Exception.new("Unable to create mailchimp lists. Response was: #{lists}") + raise Exception.new("Unable to create mailchimp lists. Response was: #{lists}") end inserted_lists = Qx.insert_into(:email_lists) - .values( lists.map{|ls| {list_name: ls[:name], mailchimp_list_id: ls[:id], tag_master_id: ls[:tag_master_id]}}) - .common_values({ nonprofit_id: npo_id, }) + .values(lists.map { |ls| {list_name: ls[:name], mailchimp_list_id: ls[:id], tag_master_id: ls[:tag_master_id]} }) + .common_values({nonprofit_id: npo_id}) .ts - .returning('*') + .returning("*") .execute Nonprofit.find(npo_id).email_lists.each(&:populate_list_later) - return {deleted:deleted.map{|i| {'mailchimp_list_id' => i.mailchimp_list_id}}, deleted_result: result, inserted_lists: inserted_lists, inserted_result: lists} + {deleted: deleted.map { |i| {"mailchimp_list_id" => i.mailchimp_list_id} }, deleted_result: result, inserted_lists: inserted_lists, inserted_result: lists} end - end - diff --git a/app/legacy_lib/insert_import.rb b/app/legacy_lib/insert_import.rb index 5cebae80e..dac4c95bc 100644 --- a/app/legacy_lib/insert_import.rb +++ b/app/legacy_lib/insert_import.rb @@ -9,22 +9,19 @@ # require 'insert/insert_tag_joins' module InsertImport - # Wrap the import in a transaction and email any errors def self.from_csv_safe(data) - begin - Qx.transaction do - InsertImport.from_csv(data) - end - rescue Exception => e - body = "Import failed. Error: #{e}" - GenericMailer.generic_mail( - 'support@commitchange.com', 'Jay Bot', # FROM - body, - 'Import error', # SUBJECT - 'support@commitchange.com', 'Jay' # TO - ).deliver + Qx.transaction do + InsertImport.from_csv(data) end + rescue Exception => e + body = "Import failed. Error: #{e}" + GenericMailer.generic_mail( + "support@commitchange.com", "Jay Bot", # FROM + body, + "Import error", # SUBJECT + "support@commitchange.com", "Jay" # TO + ).deliver end # Insert a bunch of Supporter and related data using a CSV and a bunch of header_matches @@ -49,7 +46,7 @@ def self.from_csv(data) user_id: data[:user_id] }) .timestamps - .returning('*') + .returning("*") .execute.first row_count = 0 imported_count = 0 @@ -57,106 +54,106 @@ def self.from_csv(data) created_payment_ids = [] # no spaces are allowed by open(). We could URI.encode, but spaces seem to be the only problem and we want to avoid double-encoding a URL - data[:file_uri] = data[:file_uri].gsub(/ /, '%20') + data[:file_uri] = data[:file_uri].gsub(/ /, "%20") CSV.new(open(data[:file_uri]), headers: :first_row).each do |row| row_count += 1 # triplet of [header_name, value, import_key] - matches = row.map{|key, val| [key, val, data[:header_matches][key]]} + matches = row.map { |key, val| [key, val, data[:header_matches][key]] } next if matches.empty? - table_data = matches.reduce({}) do |acc, triplet| + table_data = matches.each_with_object({}) do |triplet, acc| key, val, match = triplet - if match == 'custom_field' - acc['custom_fields'] ||= [] - acc['custom_fields'].push([key, val]) - elsif match == 'tag' - acc['tags'] ||= [] - acc['tags'].push(val) + if match == "custom_field" + acc["custom_fields"] ||= [] + acc["custom_fields"].push([key, val]) + elsif match == "tag" + acc["tags"] ||= [] + acc["tags"].push(val) else - table, col = match.split('.') if match.present? + table, col = match.split(".") if match.present? if table.present? && col.present? acc[table] ||= {} acc[table][col] = val end end - acc end # Create supporter record - if table_data['supporter'] - table_data['supporter'] = nonprofit.supporters.create( - table_data['supporter'], - imported_at: Time.current, - import: Import.find(import['id'])) - supporter_ids.push(table_data['supporter']['id']) + if table_data["supporter"] + table_data["supporter"] = nonprofit.supporters.create( + table_data["supporter"], + imported_at: Time.current, + import: Import.find(import["id"]) + ) + supporter_ids.push(table_data["supporter"]["id"]) imported_count += 1 else - table_data['supporter'] = {} + table_data["supporter"] = {} end # Create custom fields - if table_data['supporter']['id'] && table_data['custom_fields'] && table_data['custom_fields'].any? - InsertCustomFieldJoins.find_or_create(data[:nonprofit_id], [table_data['supporter']['id']], table_data['custom_fields']) + if table_data["supporter"]["id"] && table_data["custom_fields"] && table_data["custom_fields"].any? + InsertCustomFieldJoins.find_or_create(data[:nonprofit_id], [table_data["supporter"]["id"]], table_data["custom_fields"]) end - + # Create new tags - if table_data['supporter']['id'] && table_data['tags'] && table_data['tags'].any? + if table_data["supporter"]["id"] && table_data["tags"] && table_data["tags"].any? # Split tags by semicolons - tags = table_data['tags'].select{|t| t.present?}.map{|t| t.split(/[;,]/).map(&:strip)}.flatten - InsertTagJoins.find_or_create(data[:nonprofit_id], [table_data['supporter']['id']], tags) + tags = table_data["tags"].select { |t| t.present? }.map { |t| t.split(/[;,]/).map(&:strip) }.flatten + InsertTagJoins.find_or_create(data[:nonprofit_id], [table_data["supporter"]["id"]], tags) end # Create donation record - if table_data['donation'] && table_data['donation']['amount'] # must have amount. donation.date without donation.amount is no good - amount_string = table_data['donation']['amount'].gsub(/[^\d\.]/, '') - table_data['donation']['amount'] = (BigDecimal(amount_string.blank? ? 0 : amount_string) * 100).to_i - table_data['donation']['supporter_id'] = table_data['supporter']['id'] - table_data['donation']['nonprofit_id'] = data[:nonprofit_id] - table_data['donation']['date'] = Chronic.parse(table_data['donation']['date']) if table_data['donation']['date'].present? - table_data['donation']['date'] ||= Time.current - table_data['donation'] = Qx.insert_into(:donations).values(table_data['donation']).ts.returning('*').execute.first + if table_data["donation"] && table_data["donation"]["amount"] # must have amount. donation.date without donation.amount is no good + amount_string = table_data["donation"]["amount"].gsub(/[^\d\.]/, "") + table_data["donation"]["amount"] = (BigDecimal(amount_string.presence || 0) * 100).to_i + table_data["donation"]["supporter_id"] = table_data["supporter"]["id"] + table_data["donation"]["nonprofit_id"] = data[:nonprofit_id] + table_data["donation"]["date"] = Chronic.parse(table_data["donation"]["date"]) if table_data["donation"]["date"].present? + table_data["donation"]["date"] ||= Time.current + table_data["donation"] = Qx.insert_into(:donations).values(table_data["donation"]).ts.returning("*").execute.first imported_count += 1 else - table_data['donation'] = {} + table_data["donation"] = {} end # Create payment record - if table_data['donation'] && table_data['donation']['id'] - table_data['payment'] = Qx.insert_into(:payments).values({ - gross_amount: table_data['donation']['amount'], + if table_data["donation"] && table_data["donation"]["id"] + table_data["payment"] = Qx.insert_into(:payments).values({ + gross_amount: table_data["donation"]["amount"], fee_total: 0, - net_amount: table_data['donation']['amount'], - kind: 'OffsitePayment', + net_amount: table_data["donation"]["amount"], + kind: "OffsitePayment", nonprofit_id: data[:nonprofit_id], - supporter_id: table_data['supporter']['id'], - donation_id: table_data['donation']['id'], - towards: table_data['donation']['designation'], - date: table_data['donation']['date'] - }).ts.returning('*') + supporter_id: table_data["supporter"]["id"], + donation_id: table_data["donation"]["id"], + towards: table_data["donation"]["designation"], + date: table_data["donation"]["date"] + }).ts.returning("*") .execute.first imported_count += 1 else - table_data['payment'] = {} + table_data["payment"] = {} end # Create offsite payment record - if table_data['donation'] && table_data['donation']['id'] - table_data['offsite_payment'] = Qx.insert_into(:offsite_payments).values({ - gross_amount: table_data['donation']['amount'], - check_number: GetData.chain(table_data['offsite_payment'], 'check_number'), - kind: table_data['offsite_payment'] && table_data['offsite_payment']['check_number'] ? 'check' : '', + if table_data["donation"] && table_data["donation"]["id"] + table_data["offsite_payment"] = Qx.insert_into(:offsite_payments).values({ + gross_amount: table_data["donation"]["amount"], + check_number: GetData.chain(table_data["offsite_payment"], "check_number"), + kind: (table_data["offsite_payment"] && table_data["offsite_payment"]["check_number"]) ? "check" : "", nonprofit_id: data[:nonprofit_id], - supporter_id: table_data['supporter']['id'], - donation_id: table_data['donation']['id'], - payment_id: table_data['payment']['id'], - date: table_data['donation']['date'] - }).ts.returning('*') + supporter_id: table_data["supporter"]["id"], + donation_id: table_data["donation"]["id"], + payment_id: table_data["payment"]["id"], + date: table_data["donation"]["date"] + }).ts.returning("*") .execute.first imported_count += 1 else - table_data['offsite_payment'] = {} + table_data["offsite_payment"] = {} end - created_payment_ids.push(table_data['payment']['id']) if table_data['payment'] && table_data['payment']['id'] + created_payment_ids.push(table_data["payment"]["id"]) if table_data["payment"] && table_data["payment"]["id"] end # Create donation activity records @@ -164,11 +161,11 @@ def self.from_csv(data) import = Qx.update(:imports) .set(row_count: row_count, imported_count: imported_count) - .where(id: import['id']) - .returning('*') + .where(id: import["id"]) + .returning("*") .execute.first - ImportMailer.delay.import_completed_notification(import['id']) - return import + ImportMailer.delay.import_completed_notification(import["id"]) + import end end diff --git a/app/legacy_lib/insert_nonprofit_keys.rb b/app/legacy_lib/insert_nonprofit_keys.rb index 98a959c05..25b2a847c 100644 --- a/app/legacy_lib/insert_nonprofit_keys.rb +++ b/app/legacy_lib/insert_nonprofit_keys.rb @@ -1,25 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'httparty' -require 'cypher' - +require "httparty" +require "cypher" module InsertNonprofitKeys include HTTParty - def self.insert_mailchimp_access_token(npo_id, code) - form_data = "grant_type=authorization_code&client_id=#{URI.escape ENV['MAILCHIMP_OAUTH_CLIENT_ID']}&client_secret=#{ENV['MAILCHIMP_OAUTH_CLIENT_SECRET']}&redirect_uri=#{ENV['MAILCHIMP_REDIRECT_URL']}%2Fmailchimp-landing&code=#{URI.escape code}" + def self.insert_mailchimp_access_token(npo_id, code) + form_data = "grant_type=authorization_code&client_id=#{URI.escape ENV["MAILCHIMP_OAUTH_CLIENT_ID"]}&client_secret=#{ENV["MAILCHIMP_OAUTH_CLIENT_SECRET"]}&redirect_uri=#{ENV["MAILCHIMP_REDIRECT_URL"]}%2Fmailchimp-landing&code=#{URI.escape code}" - response = post('https://login.mailchimp.com/oauth2/token', { body: form_data }) - if response['error'] - raise Exception.new(response['error']) - end + response = post("https://login.mailchimp.com/oauth2/token", {body: form_data}) + if response["error"] + raise Exception.new(response["error"]) + end - nonprofit_key = Nonprofit.find(npo_id).nonprofit_key - nonprofit_key = Nonprofit.find(npo_id).build_nonprofit_key unless nonprofit_key + nonprofit_key = Nonprofit.find(npo_id).nonprofit_key + nonprofit_key ||= Nonprofit.find(npo_id).build_nonprofit_key - nonprofit_key.mailchimp_token = response['access_token'] - nonprofit_key.save! + nonprofit_key.mailchimp_token = response["access_token"] + nonprofit_key.save! - return response['access_token'] - end + response["access_token"] + end end diff --git a/app/legacy_lib/insert_payout.rb b/app/legacy_lib/insert_payout.rb index 8d183d750..38520c07c 100644 --- a/app/legacy_lib/insert_payout.rb +++ b/app/legacy_lib/insert_payout.rb @@ -10,15 +10,14 @@ # require 'param_validation' module InsertPayout - # Pass in the following inside the data hash: # - stripe_account_id # - email # - user_ip # - bank_name # options hash can have a :date (before date) for only paying out funds before a certain date (useful for only disbursing the prev month) - def self.with_stripe(np_id, data, options={}) - bigger_data = (data ? data : {}).merge(np_id: np_id) + def self.with_stripe(np_id, data, options = {}) + bigger_data = (data || {}).merge(np_id: np_id) ParamValidation.new(bigger_data, { np_id: {required: true, is_integer: true}, stripe_account_id: {not_blank: true, required: true}, @@ -28,11 +27,11 @@ def self.with_stripe(np_id, data, options={}) }) options ||= {} entities = RetrieveActiveRecordItems.retrieve_from_keys(bigger_data, Nonprofit => :np_id) - if (entities[:np_id].nonprofit_deactivation&.deactivated) + if entities[:np_id].nonprofit_deactivation&.deactivated raise ArgumentError.new("Sorry, this account has been deactivated.") end - unless (entities[:np_id].can_make_payouts?) + unless entities[:np_id].can_make_payouts? raise ArgumentError.new("Sorry, this account can't make payouts right now.") end @@ -42,67 +41,67 @@ def self.with_stripe(np_id, data, options={}) end totals = QueryPayments.get_payout_totals(payment_ids) nonprofit_currency = entities[:np_id].currency - now = Time.current + Time.current begin - stripe_transfer = StripeUtils.create_transfer(totals['net_amount'], data[:stripe_account_id], nonprofit_currency) - Psql.transaction do - # Create the Transfer on Stripe + stripe_transfer = StripeUtils.create_transfer(totals["net_amount"], data[:stripe_account_id], nonprofit_currency) + Psql.transaction do + # Create the Transfer on Stripe - # Retrieve all payments with available charges and undisbursed refunds - # Mark all the above payments as disbursed - UpdateCharges.disburse_all_with_payments(payment_ids) - # Mark all the above refunds as disbursed - UpdateRefunds.disburse_all_with_payments(payment_ids) - # Mark all disputes as lost_and_paid - UpdateDisputes.disburse_all_with_payments(payment_ids) - # mark all balances adjustments as disbursed - UpdateManualBalanceAdjustments.disburse_all_with_payments(payment_ids) - # Get gross total, total fees, net total, and total count - # Create the payout record (whether it succeeded on Stripe or not) - payout = Psql.execute( + # Retrieve all payments with available charges and undisbursed refunds + # Mark all the above payments as disbursed + UpdateCharges.disburse_all_with_payments(payment_ids) + # Mark all the above refunds as disbursed + UpdateRefunds.disburse_all_with_payments(payment_ids) + # Mark all disputes as lost_and_paid + UpdateDisputes.disburse_all_with_payments(payment_ids) + # mark all balances adjustments as disbursed + UpdateManualBalanceAdjustments.disburse_all_with_payments(payment_ids) + # Get gross total, total fees, net total, and total count + # Create the payout record (whether it succeeded on Stripe or not) + payout = Psql.execute( + Qexpr.new.insert(:payouts, [{ + net_amount: totals["net_amount"], + nonprofit_id: np_id, + failure_message: stripe_transfer["failure_message"], + status: stripe_transfer["status"], + fee_total: totals["fee_total"], + gross_amount: totals["gross_amount"], + email: data[:email], + count: totals["count"], + stripe_transfer_id: stripe_transfer.id, + user_ip: data[:user_ip], + ach_fee: 0, + bank_name: data[:bank_name], + houid: Payout.generate_houid + }]) + .returning("id", "net_amount", "nonprofit_id", "created_at", "updated_at", "status", "fee_total", "gross_amount", "email", "count", "stripe_transfer_id", "user_ip", "ach_fee", "bank_name", "houid") + ).first + # Create PaymentPayout records linking all the payments to the payout + Psql.execute(Qexpr.new.insert("payment_payouts", payment_ids.map { |id| {payment_id: id.to_i} }, {common_data: {payout_id: payout["id"].to_i}})) + # Create ObjectEvent record for payout.created + Payout.find(payout["id"].to_i).publish_created + NonprofitMailer.delay.pending_payout_notification(payout["id"].to_i) + payout + end + rescue Stripe::StripeError => e + Psql.execute( Qexpr.new.insert(:payouts, [{ - net_amount: totals['net_amount'], + net_amount: totals["net_amount"], nonprofit_id: np_id, - failure_message: stripe_transfer['failure_message'], - status: stripe_transfer['status'], - fee_total: totals['fee_total'], - gross_amount: totals['gross_amount'], + failure_message: e.message, + status: "failed", + fee_total: totals["fee_total"], + gross_amount: totals["gross_amount"], email: data[:email], - count: totals['count'], - stripe_transfer_id: stripe_transfer.id, + count: totals["count"], + stripe_transfer_id: nil, user_ip: data[:user_ip], ach_fee: 0, bank_name: data[:bank_name], - houid: Payout.generate_houid}]) - .returning('id', 'net_amount', 'nonprofit_id', 'created_at', 'updated_at', 'status', 'fee_total', 'gross_amount', 'email', 'count', 'stripe_transfer_id', 'user_ip', 'ach_fee', 'bank_name', 'houid') - ).first - # Create PaymentPayout records linking all the payments to the payout - pps = Psql.execute(Qexpr.new.insert('payment_payouts', payment_ids.map{|id| {payment_id: id.to_i}}, {common_data: {payout_id: payout['id'].to_i}})) - # Create ObjectEvent record for payout.created - Payout.find(payout['id'].to_i).publish_created - NonprofitMailer.delay.pending_payout_notification(payout['id'].to_i) - payout - end - rescue Stripe::StripeError => e - payout = Psql.execute( - Qexpr.new.insert(:payouts, [{ - net_amount: totals['net_amount'], - nonprofit_id: np_id, - failure_message: e.message, - status: 'failed', - fee_total: totals['fee_total'], - gross_amount: totals['gross_amount'], - email: data[:email], - count: totals['count'], - stripe_transfer_id: nil, - user_ip: data[:user_ip], - ach_fee: 0, - bank_name: data[:bank_name], - houid: Payout.generate_houid - }]) - .returning('id', 'net_amount', 'nonprofit_id', 'created_at', 'updated_at', 'status', 'fee_total', 'gross_amount', 'email', 'count', 'stripe_transfer_id', 'user_ip', 'ach_fee', 'bank_name', 'houid') + houid: Payout.generate_houid + }]) + .returning("id", "net_amount", "nonprofit_id", "created_at", "updated_at", "status", "fee_total", "gross_amount", "email", "count", "stripe_transfer_id", "user_ip", "ach_fee", "bank_name", "houid") ).first - return payout end end end diff --git a/app/legacy_lib/insert_recurring_donation.rb b/app/legacy_lib/insert_recurring_donation.rb index bd326eece..7800b4588 100644 --- a/app/legacy_lib/insert_recurring_donation.rb +++ b/app/legacy_lib/insert_recurring_donation.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertRecurringDonation - # Create a recurring_donation, donation, payment, charge, and activity # See controllers/nonprofits/recurring_donations_controller#create for the data params to pass in def self.with_stripe(data) @@ -9,31 +8,31 @@ def self.with_stripe(data) ParamValidation.new(data, InsertDonation.common_param_validations .merge(token: {required: true, format: UUID::Regex})) - unless data[:recurring_donation].nil? + if data[:recurring_donation].nil? + data[:recurring_donation] = {} + else ParamValidation.new(data[:recurring_donation], { - interval: {is_integer: true}, - start_date: {can_be_date: true}, - time_unit: {included_in: %w(month day week year)}, - paydate: {is_integer:true} + interval: {is_integer: true}, + start_date: {can_be_date: true}, + time_unit: {included_in: %w[month day week year]}, + paydate: {is_integer: true} }) - if (data[:recurring_donation][:paydate]) + if data[:recurring_donation][:paydate] data[:recurring_donation][:paydate] = data[:recurring_donation][:paydate].to_i end ParamValidation.new(data[:recurring_donation], { - paydate: {min:1, max:28} + paydate: {min: 1, max: 28} }) - else - data[:recurring_donation] = {} end source_token = QuerySourceToken.get_and_increment_source_token(data[:token], nil) tokenizable = source_token.tokenizable QuerySourceToken.validate_source_token_type(source_token) - entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) + entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) entities = entities.merge(RetrieveActiveRecordItems.retrieve_from_keys(data, {Campaign => :campaign_id, Event => :event_id, Profile => :profile_id}, true)) @@ -44,36 +43,36 @@ def self.with_stripe(data) raise ParamValidation::ValidationError.new("Supporter #{entities[:supporter_id].id} does not own card #{tokenizable.id}", key: :token) end - data['card_id'] = tokenizable.id + data["card_id"] = tokenizable.id result = {} data[:date] = Time.now data = data.merge(payment_provider: payment_provider(data)) - data = data.except(:old_donation).except('old_donation') + data = data.except(:old_donation).except("old_donation") # if start date is today, make initial charge first test_start_date = get_test_start_date(data) - if test_start_date == nil || Time.current >= test_start_date + if test_start_date.nil? || Time.current >= test_start_date result = result.merge(InsertDonation.insert_charge(data)) - if result['charge']['status'] == 'failed' - raise ChargeError.new(result['charge']['failure_message']) + if result["charge"]["status"] == "failed" + raise ChargeError.new(result["charge"]["failure_message"]) end end # Create the donation record - result['donation'] = InsertDonation.insert_donation(data, entities) - entities[:donation_id] = result['donation'] + result["donation"] = InsertDonation.insert_donation(data, entities) + entities[:donation_id] = result["donation"] # Create the recurring_donation record - result['recurring_donation'] = insert_recurring_donation(data,entities) + result["recurring_donation"] = insert_recurring_donation(data, entities) # Update charge foreign keys - if result['payment'] + if result["payment"] InsertDonation.update_donation_keys(result) # Create the activity record - result['activity'] = InsertActivities.for_recurring_donations([result['payment'].id]) + result["activity"] = InsertActivities.for_recurring_donations([result["payment"].id]) end # Send receipts - JobQueue.queue(JobTypes::DonationPaymentCreateJob, result['donation'].id, result['payment']&.id, entities[:supporter_id].locale) - return result + JobQueue.queue(JobTypes::DonationPaymentCreateJob, result["donation"].id, result["payment"]&.id, entities[:supporter_id].locale) + result end def self.with_sepa(data) @@ -85,53 +84,53 @@ def self.with_sepa(data) result = result.merge(InsertDonation.insert_charge(data)) end - result['donation'] = Psql.execute(Qexpr.new.insert(:donations, [ + result["donation"] = Psql.execute(Qexpr.new.insert(:donations, [ data.except(:recurring_donation) - ]).returning('*')).first + ]).returning("*")).first - result['recurring_donation'] = Psql.execute(Qexpr.new.insert(:recurring_donations, [ - data[:recurring_donation].merge(donation_id: result['donation']['id']) - ]).returning('*')).first + result["recurring_donation"] = Psql.execute(Qexpr.new.insert(:recurring_donations, [ + data[:recurring_donation].merge(donation_id: result["donation"]["id"]) + ]).returning("*")).first - if result['payment'] + if result["payment"] InsertDonation.update_donation_keys(result) end - DonationMailer.delay.nonprofit_payment_notification(result['donation']['id']) - DonationMailer.delay.donor_direct_debit_notification(result['donation']['id'], Supporter.find(result['donation']['supporter_id']).locale) + DonationMailer.delay.nonprofit_payment_notification(result["donation"]["id"]) + DonationMailer.delay.donor_direct_debit_notification(result["donation"]["id"], Supporter.find(result["donation"]["supporter_id"]).locale) - { status: 200, json: result } + {status: 200, json: result} end def self.import_with_stripe(data) data = data.to_deprecated_h.with_indifferent_access ParamValidation.new(data, InsertDonation.common_param_validations - .merge(card_id: {required: true, is_reference:true})) + .merge(card_id: {required: true, is_reference: true})) - unless data[:recurring_donation].nil? + if data[:recurring_donation].nil? + data[:recurring_donation] = {} + else ParamValidation.new(data[:recurring_donation], { - interval: {is_integer: true}, - start_date: {can_be_date: true}, - time_unit: {included_in: %w(month day week year)}, - paydate: {is_integer:true} + interval: {is_integer: true}, + start_date: {can_be_date: true}, + time_unit: {included_in: %w[month day week year]}, + paydate: {is_integer: true} }) - if (data[:recurring_donation][:paydate]) + if data[:recurring_donation][:paydate] data[:recurring_donation][:paydate] = data[:recurring_donation][:paydate].to_i end ParamValidation.new(data[:recurring_donation], { - paydate: {min:1, max:28} + paydate: {min: 1, max: 28} }) - else - data[:recurring_donation] = {} end - card = Card.find(data['card_id']) + card = Card.find(data["card_id"]) - entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) + entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id}) entities = entities.merge(RetrieveActiveRecordItems.retrieve_from_keys(data, {Campaign => :campaign_id, Event => :event_id, Profile => :profile_id}, true)) @@ -142,15 +141,15 @@ def self.import_with_stripe(data) raise ParamValidation::ValidationError.new("Supporter #{entities[:supporter_id].id} does not own card #{card.id}", key: :token) end - data['card_id'] = card.id + data["card_id"] = card.id result = {} data[:date] = Time.now data = data.merge(payment_provider: payment_provider(data)) - data = data.except(:old_donation).except('old_donation') + data = data.except(:old_donation).except("old_donation") # if start date is today, make initial charge first test_start_date = get_test_start_date(data) - if test_start_date == nil || Time.current >= test_start_date + if test_start_date.nil? || Time.current >= test_start_date puts "we would have charged on #{data}" # result = result.merge(InsertDonation.insert_charge(data)) @@ -160,29 +159,28 @@ def self.import_with_stripe(data) end # Create the donation record - result['donation'] = InsertDonation.insert_donation(data, entities) - entities[:donation_id] = result['donation'] + result["donation"] = InsertDonation.insert_donation(data, entities) + entities[:donation_id] = result["donation"] # Create the recurring_donation record - result['recurring_donation'] = insert_recurring_donation(data,entities) + result["recurring_donation"] = insert_recurring_donation(data, entities) # Update charge foreign keys - if result['payment'] + if result["payment"] InsertDonation.update_donation_keys(result) # Create the activity record - result['activity'] = InsertActivities.for_recurring_donations([result['payment'].id]) + result["activity"] = InsertActivities.for_recurring_donations([result["payment"].id]) end - return result + result end - - # the data model here is brutal. This needs to get cleaned up. + # the data model here is brutal. This needs to get cleaned up. def self.convert_donation_to_recurring_donation(donation_id) - ParamValidation.new({donation_id: donation_id}, {donation_id: {:required => true, :is_integer => true}}) - don = Donation.where('id = ? ', donation_id).first + ParamValidation.new({donation_id: donation_id}, {donation_id: {required: true, is_integer: true}}) + don = Donation.where("id = ? ", donation_id).first if !don - raise ParamValidation::ValidationError.new("#{donation_id} is not a valid donation", {:key => :donation_id, :val => donation_id}) + raise ParamValidation::ValidationError.new("#{donation_id} is not a valid donation", {key: :donation_id, val: donation_id}) end - rd = insert_recurring_donation({amount:don.amount, email: don.supporter.email, anonymous: don.anonymous, origin_url: don.origin_url, recurring_donation: { start_date: don.created_at, :paydate => convert_date_to_valid_paydate(don.created_at)}, date: don.created_at}, {supporter_id: don.supporter, nonprofit_id: don.nonprofit, donation_id: don}) + rd = insert_recurring_donation({amount: don.amount, email: don.supporter.email, anonymous: don.anonymous, origin_url: don.origin_url, recurring_donation: {start_date: don.created_at, paydate: convert_date_to_valid_paydate(don.created_at)}, date: don.created_at}, {supporter_id: don.supporter, nonprofit_id: don.nonprofit, donation_id: don}) don.recurring_donation = rd don.recurring = true @@ -194,7 +192,7 @@ def self.convert_donation_to_recurring_donation(donation_id) rd end - def self.insert_recurring_donation(data, entities) + def self.insert_recurring_donation(data, entities) rd = RecurringDonation.new rd.amount = data[:amount] rd.anonymous = data[:anonymous] @@ -203,41 +201,39 @@ def self.insert_recurring_donation(data, entities) rd.supporter_id = entities[:supporter_id].id rd.active = true rd.edit_token = SecureRandom.uuid - rd.n_failures= 0 - rd.email= entities[:supporter_id].email - rd.interval = data[:recurring_donation][:interval].blank? ? 1 : data[:recurring_donation][:interval] - rd.time_unit= data[:recurring_donation][:time_unit].blank? ? 'month' : data[:recurring_donation][:time_unit] - if data[:recurring_donation][:start_date].blank? - rd.start_date= Time.current.beginning_of_day + rd.n_failures = 0 + rd.email = entities[:supporter_id].email + rd.interval = (data[:recurring_donation][:interval].presence || 1) + rd.time_unit = (data[:recurring_donation][:time_unit].presence || "month") + rd.start_date = if data[:recurring_donation][:start_date].blank? + Time.current.beginning_of_day elsif data[:recurring_donation][:start_date].is_a? Time - rd.start_date = data[:recurring_donation][:start_date] + data[:recurring_donation][:start_date] else - rd.start_date = Chronic.parse(data[:recurring_donation][:start_date]) + Chronic.parse(data[:recurring_donation][:start_date]) end - if rd.time_unit == 'month' && rd.interval == 1 && data[:recurring_donation][:paydate].nil? - rd.paydate = convert_date_to_valid_paydate(rd.start_date) + rd.paydate = if rd.time_unit == "month" && rd.interval == 1 && data[:recurring_donation][:paydate].nil? + convert_date_to_valid_paydate(rd.start_date) else - rd.paydate = data[:recurring_donation][:paydate] + data[:recurring_donation][:paydate] end rd.save! - misc = rd.misc_recurring_donation_info || rd.create_misc_recurring_donation_info misc.fee_covered = data[:fee_covered] misc.save! - + rd end -def self.get_test_start_date(data) + + def self.get_test_start_date(data) unless data[:recurring_donation] && data[:recurring_donation][:start_date] return nil end - return Chronic.parse(data[:recurring_donation][:start_date]) - - + Chronic.parse(data[:recurring_donation][:start_date]) end def self.payment_provider(data) @@ -250,6 +246,6 @@ def self.payment_provider(data) def self.convert_date_to_valid_paydate(date) day = date.day - return day > 28 ? 28 : day + (day > 28) ? 28 : day end end diff --git a/app/legacy_lib/insert_refunds.rb b/app/legacy_lib/insert_refunds.rb index fb646ae32..eb0fadfb1 100644 --- a/app/legacy_lib/insert_refunds.rb +++ b/app/legacy_lib/insert_refunds.rb @@ -1,16 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertRefunds - # Refund a given charge, up to its net amount # params: amount, donation obj def self.with_stripe(charge, h) modern_refund(charge, h) end - - def self.modern_refund(charge,h) - ParamValidation.new(charge, { + def self.modern_refund(charge, h) + ParamValidation.new(charge, { payment_id: {required: true, is_integer: true}, stripe_charge_id: {required: true, format: /^(test_)?ch_.*$/}, amount: {required: true, is_integer: true, min: 1}, @@ -18,59 +16,57 @@ def self.modern_refund(charge,h) nonprofit_id: {required: true, is_integer: true}, supporter_id: {required: true, is_integer: true} }) - ParamValidation.new(h, { amount: {required: true, is_integer: true, min: 1} }) - original_payment = Payment.find(charge['payment_id']) + ParamValidation.new(h, {amount: {required: true, is_integer: true, min: 1}}) + original_payment = Payment.find(charge["payment_id"]) - if original_payment.refund_total.to_i + h['amount'].to_i > original_payment.gross_amount.to_i - raise RuntimeError.new("Refund amount must be less than the net amount of the payment (for charge #{charge['id']})") + if original_payment.refund_total.to_i + h["amount"].to_i > original_payment.gross_amount.to_i + raise "Refund amount must be less than the net amount of the payment (for charge #{charge["id"]})" end - refund_data = {'amount' => h['amount'], 'charge' => charge['stripe_charge_id']} - refund_data['reason'] = h['reason'] unless h['reason'].blank? # Stripe will error on blank reason field - - results = InsertRefunds.perform_stripe_refund(nonprofit_id:charge['nonprofit_id'], refund_data:refund_data, charge_date: charge['created_at']) + refund_data = {"amount" => h["amount"], "charge" => charge["stripe_charge_id"]} + refund_data["reason"] = h["reason"] unless h["reason"].blank? # Stripe will error on blank reason field - Refund.transaction do + results = InsertRefunds.perform_stripe_refund(nonprofit_id: charge["nonprofit_id"], refund_data: refund_data, charge_date: charge["created_at"]) - refund = Refund.create!({amount: h['amount'], - comment: h['comment'], - reason: h['reason'], + Refund.transaction do + refund = Refund.create!({amount: h["amount"], + comment: h["comment"], + reason: h["reason"], stripe_refund_id: results[:stripe_refund].id, - charge_id: charge['id'] - }) + charge_id: charge["id"]}) refund.create_misc_refund_info(is_modern: true, stripe_application_fee_refund_id: results[:stripe_app_fee_refund]&.id) - gross = -(h['amount']) + gross = -h["amount"] fees = (results[:stripe_app_fee_refund] && results[:stripe_app_fee_refund].amount) || 0 net = gross + fees - + # Create a corresponding./run negative payment record payment = Payment.create!({ - gross_amount: gross, - fee_total: fees, - net_amount: net, - kind: 'Refund', - towards: original_payment.towards, - date: refund.created_at, - nonprofit_id: charge['nonprofit_id'], - supporter_id: charge['supporter_id'] - }) + gross_amount: gross, + fee_total: fees, + net_amount: net, + kind: "Refund", + towards: original_payment.towards, + date: refund.created_at, + nonprofit_id: charge["nonprofit_id"], + supporter_id: charge["supporter_id"] + }) InsertActivities.for_refunds([payment.id]) # Update the refund to have the above payment_id refund.payment = payment refund.save! - + # Update original payment to increment its refund_total for any future refund attempts - original_payment.refund_total += h['amount'].to_i + original_payment.refund_total += h["amount"].to_i original_payment.save! # Send the refund receipts in a delayed job - + JobQueue.queue JobTypes::RefundCreatedJob, refund - - {'payment' => payment.attributes, 'refund' => refund.attributes} + + {"payment" => payment.attributes, "refund" => refund.attributes} end end @@ -78,15 +74,14 @@ def self.modern_refund(charge,h) # @option opts [Hash] :refund_data the data to pass to the Stripe::Refund#create method # @option opts [Integer] :nonprofit_id the nonprofit_id that the charge belongs to # @option opts [Time] :charge_date the time that the charge to be refunded occurred - def self.perform_stripe_refund(opts={}) - refund_data = opts[:refund_data].merge({'reverse_transfer' => true, expand: ['charge']}) - stripe_refund = Stripe::Refund.create(refund_data, {stripe_version: '2019-09-09'}) - stripe_app_fee = Stripe::ApplicationFee.retrieve({id: stripe_refund.charge.application_fee}, {stripe_version: '2019-09-09'}) - fee_to_refund = Nonprofit.find(opts[:nonprofit_id]).calculate_application_fee_refund(refund:stripe_refund, charge:stripe_refund.charge, application_fee:stripe_app_fee, charge_date: opts[:charge_date]) + def self.perform_stripe_refund(opts = {}) + refund_data = opts[:refund_data].merge({"reverse_transfer" => true, :expand => ["charge"]}) + stripe_refund = Stripe::Refund.create(refund_data, {stripe_version: "2019-09-09"}) + stripe_app_fee = Stripe::ApplicationFee.retrieve({id: stripe_refund.charge.application_fee}, {stripe_version: "2019-09-09"}) + fee_to_refund = Nonprofit.find(opts[:nonprofit_id]).calculate_application_fee_refund(refund: stripe_refund, charge: stripe_refund.charge, application_fee: stripe_app_fee, charge_date: opts[:charge_date]) if fee_to_refund > 0 - app_fee_refund = Stripe::ApplicationFee.create_refund(stripe_refund.charge.application_fee, {amount: fee_to_refund}, {stripe_version: '2019-09-09'}) + app_fee_refund = Stripe::ApplicationFee.create_refund(stripe_refund.charge.application_fee, {amount: fee_to_refund}, {stripe_version: "2019-09-09"}) end {stripe_refund: stripe_refund, stripe_app_fee_refund: app_fee_refund} end end - diff --git a/app/legacy_lib/insert_source_token.rb b/app/legacy_lib/insert_source_token.rb index ece45da24..2779eb8e4 100644 --- a/app/legacy_lib/insert_source_token.rb +++ b/app/legacy_lib/insert_source_token.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertSourceToken - - def self.create_record(tokenizable, params={}) - ParamValidation.new({tokenizable:tokenizable}.merge(params), { - tokenizable: {required:true}, - event: {is_a: Event}, - expiration_time: {is_integer: true, min: 1}, - max_uses: {is_integer: true, min: 1} + def self.create_record(tokenizable, params = {}) + ParamValidation.new({tokenizable: tokenizable}.merge(params), { + tokenizable: {required: true}, + event: {is_a: Event}, + expiration_time: {is_integer: true, min: 1}, + max_uses: {is_integer: true, min: 1} }) - if (params[:event] != nil) + if !params[:event].nil? max_uses = params[:max_uses] || Settings.source_tokens.event_donation_source.max_uses expiration_diff = params[:expiration_time] || Settings.source_tokens.event_donation_source.time_after_event expiration = params[:event].end_datetime + expiration_diff.to_i @@ -26,6 +25,4 @@ def self.create_record(tokenizable, params={}) c.save! c end - - -end \ No newline at end of file +end diff --git a/app/legacy_lib/insert_supporter.rb b/app/legacy_lib/insert_supporter.rb index b1330c9a6..be05ce974 100644 --- a/app/legacy_lib/insert_supporter.rb +++ b/app/legacy_lib/insert_supporter.rb @@ -1,34 +1,33 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertSupporter - - def self.create_or_update(np_id, data, update=false) - if (BLOCKED_SUPPORTERS.include?(data[:email])) + def self.create_or_update(np_id, data, update = false) + if BLOCKED_SUPPORTERS.include?(data[:email]) raise "Blocked supporter" end ParamValidation.new(data.merge(np_id: np_id), { np_id: {required: true, is_integer: true} }) - address_keys = ['name', 'address', 'city', 'country', 'state_code'] - custom_fields = data['customFields'] - tags = data['tags'] - data = HashWithIndifferentAccess.new(Format::RemoveDiacritics.from_hash(data.to_deprecated_h, address_keys)) + address_keys = ["name", "address", "city", "country", "state_code"] + custom_fields = data["customFields"] + tags = data["tags"] + data = ActiveSupport::HashWithIndifferentAccess.new(Format::RemoveDiacritics.from_hash(data.to_deprecated_h, address_keys)) .except(:customFields, :tags) nonprofit = Nonprofit.find(np_id) supporter = nonprofit.supporters.not_deleted.where("name = ? AND email = ?", data[:name], data[:email]).first - if supporter && update + if supporter && update supporter.update(data) - else + else supporter = nonprofit.supporters.create(data) supporter.publish_created - end + end - InsertCustomFieldJoins.find_or_create(np_id, [supporter['id']], custom_fields) if custom_fields.present? - InsertTagJoins.find_or_create(np_id, [supporter['id']], tags) if tags.present? + InsertCustomFieldJoins.find_or_create(np_id, [supporter["id"]], custom_fields) if custom_fields.present? + InsertTagJoins.find_or_create(np_id, [supporter["id"]], tags) if tags.present? - #GeocodeModel.delay.supporter(supporter['id']) - return supporter + # GeocodeModel.delay.supporter(supporter['id']) + supporter end # pass in a hash of supporter info, as well as @@ -44,15 +43,14 @@ def self.create_or_update(np_id, data, update=false) # The above will create a supporter with name/email, one tag with name 'xy', # and one field with name 'xy' and value 420 def self.with_tags_and_fields(np_id, data) - tags = data.select{|key, val| key.match(/^tag_/)}.map{|key, val| key.gsub('tag_', '')} - fields = data.select{|key, val| key.match(/^field_/)}.map{|key, val| [key.gsub('field_', ''), val]} - supp_cols = data.select{|key, val| !key.match(/^field_/) && !key.match(/^tag_/)} + tags = data.select { |key, val| key.match(/^tag_/) }.map { |key, val| key.gsub("tag_", "") } + fields = data.select { |key, val| key.match(/^field_/) }.map { |key, val| [key.gsub("field_", ""), val] } + supp_cols = data.select { |key, val| !key.match(/^field_/) && !key.match(/^tag_/) } supporter = create_or_update(np_id, supp_cols) - InsertTagJoins.delay.find_or_create(np_id, [supporter['id']], tags) if tags.any? - InsertCustomFieldJoins.delay.find_or_create(np_id, [supporter['id']], fields) if fields.any? + InsertTagJoins.delay.find_or_create(np_id, [supporter["id"]], tags) if tags.any? + InsertCustomFieldJoins.delay.find_or_create(np_id, [supporter["id"]], fields) if fields.any? - return supporter + supporter end - end diff --git a/app/legacy_lib/insert_tag_joins.rb b/app/legacy_lib/insert_tag_joins.rb index bd9d1feff..a7c1f3640 100644 --- a/app/legacy_lib/insert_tag_joins.rb +++ b/app/legacy_lib/insert_tag_joins.rb @@ -1,10 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'psql' -require 'qx' +require "psql" +require "qx" module InsertTagJoins - - # @param [Integer] np_id id for a [Nonprofit] # @param [Integer] profile_id id for the [Profile] corresponding to the current user. Not used currently but needed # @param [Array] supporter_ids the ids of the all the supporters whose tags should be changed. @@ -23,11 +21,10 @@ def self.in_bulk(np_id, profile_id, supporter_ids, tag_data) np_id: {required: true, is_integer: true}, profile_id: {required: true, is_integer: true}, supporter_ids: {is_array: true}, - tag_data: { required: true - # array_of_hashes: { - # selected: {required: true}, tag_master_id: {required: true, is_integer: true} - # } - } + tag_data: {required: true} + # array_of_hashes: { + # selected: {required: true}, tag_master_id: {required: true, is_integer: true} + # } }) rescue ParamValidation::ValidationError => e return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity} @@ -50,7 +47,6 @@ def self.in_bulk(np_id, profile_id, supporter_ids, tag_data) valid_ids = nonprofit.tag_masters.where("id IN (?)", tag_data.to_tag_master_ids).pluck(:id).to_a filtered_tag_data = tag_data.for_given_tags(valid_ids) - # first, delete the items which should be removed to_remove = filtered_tag_data.unselected.to_tag_master_ids deleted = [] @@ -58,23 +54,23 @@ def self.in_bulk(np_id, profile_id, supporter_ids, tag_data) deleted = Qx.delete_from(:tag_joins) .where("supporter_id IN ($ids)", ids: supporter_ids) .and_where("tag_master_id in ($tags)", tags: to_remove) - .returning('*') + .returning("*") .execute end # next add only the selected tag_joins to_insert = filtered_tag_data.selected.to_tag_master_ids - insert_data = supporter_ids.map{|id| to_insert.map{|tag_master_id| {supporter_id: id, tag_master_id: tag_master_id}}}.flatten - if insert_data.any? - tags = Qx.insert_into(:tag_joins) + insert_data = supporter_ids.map { |id| to_insert.map { |tag_master_id| {supporter_id: id, tag_master_id: tag_master_id} } }.flatten + tags = if insert_data.any? + Qx.insert_into(:tag_joins) .values(insert_data) .timestamps - .on_conflict() + .on_conflict .conflict_columns(:supporter_id, :tag_master_id).upsert(:tag_join_supporter_unique_idx) - .returning('*') + .returning("*") .execute else - tags = [] + [] end rescue ActiveRecord::ActiveRecordError => e return {json: {error: "A DB error occurred. Please contact support. \n #{e.message}"}, status: :unprocessable_entity} @@ -88,10 +84,9 @@ def self.in_bulk(np_id, profile_id, supporter_ids, tag_data) # Sync mailchimp lists, if present Mailchimp.delay.sync_supporters_to_list_from_tag_joins(np_id, supporter_ids, tag_data) - return {json: {inserted_count: tags.count, removed_count: deleted.count }, status: :ok} + {json: {inserted_count: tags.count, removed_count: deleted.count}, status: :ok} end - # Find or create many tag names for every supporter # Creates tag masters for tag names that are not present def self.find_or_create(np_id, supporter_ids, tag_names) @@ -105,23 +100,19 @@ def self.find_or_create(np_id, supporter_ids, tag_names) tm = Qx.insert_into(:tag_masters).values({ name: name, nonprofit_id: np_id - }).ts.returning('id').execute.last + }).ts.returning("id").execute.last end - [name, tm['id']] + [name, tm["id"]] end tag_join_data = supporter_ids.map do |id| - tags.map{|name, tm_id| {supporter_id: id, tag_master_id: tm_id}} + tags.map { |name, tm_id| {supporter_id: id, tag_master_id: tm_id} } end.flatten - tag_joins = Qx.insert_into(:tag_joins) + Qx.insert_into(:tag_joins) .values(tag_join_data) - .ts.returning('id').execute - - return tag_joins + .ts.returning("id").execute end private - - end diff --git a/app/legacy_lib/insert_tickets.rb b/app/legacy_lib/insert_tickets.rb index dc28f17a9..c3476010e 100644 --- a/app/legacy_lib/insert_tickets.rb +++ b/app/legacy_lib/insert_tickets.rb @@ -1,10 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module InsertTickets - - - - # Will generate rows for payment, offsite_payment or charge, tickets, activities # pass in: # data: { @@ -19,7 +15,7 @@ module InsertTickets # amount: integer # fee_covered: boolean # } - def self.create(data, skip_notifications=false) + def self.create(data, skip_notifications = false) data = data.to_deprecated_h.with_indifferent_access ParamValidation.new(data, { tickets: {required: true, is_array: true}, @@ -27,19 +23,19 @@ def self.create(data, skip_notifications=false) supporter_id: {required: true, is_reference: true}, event_id: {required: true, is_reference: true}, event_discount_id: {is_reference: true}, - kind: {included_in: ['free', 'charge', 'offsite']}, + kind: {included_in: ["free", "charge", "offsite"]}, token: {format: UUID::Regex}, offsite_payment: {is_hash: true}, amount: {required: true, is_integer: true} }) - data[:tickets].each {|t| + data[:tickets].each { |t| ParamValidation.new(t, {quantity: {is_integer: true, required: true, min: 1}, ticket_level_id: {is_reference: true, required: true}}) } - ParamValidation.new(data[:offsite_payment], {kind: {included_in: %w(cash check)}}) if data[:offsite_payment] && !data[:offsite_payment][:kind].blank? + ParamValidation.new(data[:offsite_payment], {kind: {included_in: %w[cash check]}}) if data[:offsite_payment] && !data[:offsite_payment][:kind].blank? - entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id, Event => :event_id}) + entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id, Event => :event_id}) entities.merge!(RetrieveActiveRecordItems.retrieve_from_keys(data, {EventDiscount => :event_discount_id}, true)) @@ -47,22 +43,21 @@ def self.create(data, skip_notifications=false) validate_entities(entities, tl_entities) - #verify that enough tickets_available + # verify that enough tickets_available QueryTicketLevels.verify_tickets_available(data[:tickets]) estimated_gross_amount = QueryTicketLevels.gross_amount_from_tickets(data[:tickets], data[:event_discount_id]) gross_amount = data[:amount] - if (gross_amount < estimated_gross_amount) + if gross_amount < estimated_gross_amount raise ParamValidation::ValidationError.new("You authorized a payment of $#{Format::Currency.cents_to_dollars(gross_amount)} but the total value of tickets requested was $#{Format::Currency.cents_to_dollars(estimated_gross_amount)}.", key: :amount) end - - + result = {} - trx = entities[:supporter_id].transactions.build(amount:0, created:Time.current) + trx = entities[:supporter_id].transactions.build(amount: 0, created: Time.current) tktpur = trx.ticket_purchases.build if gross_amount > 0 # Create offsite payment for tickets - if data[:kind] == 'offsite' + if data[:kind] == "offsite" current_user = data[:current_user] # offsite can only come from valid nonprofit users unless current_user && QueryRoles.is_authorized_for_nonprofit?(current_user.id, entities[:nonprofit_id].id) @@ -70,27 +65,27 @@ def self.create(data, skip_notifications=false) end # create payment and offsite payment - result['payment'] = create_payment(entities, gross_amount) - result['offsite_payment'] = create_offsite_payment(entities, gross_amount, data, result['payment']) - - trx.assign_attributes(amount: result['payment'].gross_amount, created: result['payment'].date) - + result["payment"] = create_payment(entities, gross_amount) + result["offsite_payment"] = create_offsite_payment(entities, gross_amount, data, result["payment"]) + + trx.assign_attributes(amount: result["payment"].gross_amount, created: result["payment"].date) - legacy_payment = Payment.find(result['payment']['id']) + legacy_payment = Payment.find(result["payment"]["id"]) trx_charge = SubtransactionPayment.new( legacy_payment: legacy_payment, paymentable: OfflineTransactionCharge.new, created: legacy_payment.date ) - subtrx = trx.build_subtransaction( - subtransactable: OfflineTransaction.new(amount: result['payment'].gross_amount), - subtransaction_payments:[ + subtrx = trx.build_subtransaction( + subtransactable: OfflineTransaction.new(amount: result["payment"].gross_amount), + subtransaction_payments: [ trx_charge - ]) + ] + ) # Create charge for tickets - elsif data['kind'] == 'charge' || !data['kind'] - source_token = QuerySourceToken.get_and_increment_source_token(data[:token],nil) + elsif data["kind"] == "charge" || !data["kind"] + source_token = QuerySourceToken.get_and_increment_source_token(data[:token], nil) QuerySourceToken.validate_source_token_type(source_token) tokenizable = source_token.tokenizable @@ -112,37 +107,38 @@ def self.create(data, skip_notifications=false) nonprofit_id: entities[:nonprofit_id].id, supporter_id: entities[:supporter_id].id, card_id: tokenizable.id, - fee_covered:data[:fee_covered] + fee_covered: data[:fee_covered] })) - if result['charge']['status'] == 'failed' - raise ChargeError.new(result['charge']['failure_message']) + if result["charge"]["status"] == "failed" + raise ChargeError.new(result["charge"]["failure_message"]) end - trx.assign_attributes(amount: result['payment'].gross_amount, created: result['payment'].date) + trx.assign_attributes(amount: result["payment"].gross_amount, created: result["payment"].date) - legacy_payment = Payment.find(result['payment']['id']) + legacy_payment = Payment.find(result["payment"]["id"]) trx_charge = SubtransactionPayment.new( legacy_payment: legacy_payment, paymentable: StripeTransactionCharge.new, created: legacy_payment.date ) - subtrx = trx.build_subtransaction( - subtransactable: StripeTransaction.new(amount: result['payment'].gross_amount), - subtransaction_payments:[ + subtrx = trx.build_subtransaction( + subtransactable: StripeTransaction.new(amount: result["payment"].gross_amount), + subtransaction_payments: [ trx_charge - ]) + ] + ) else raise ParamValidation::ValidationError.new("Ticket costs money but you didn't pay.", {key: :kind}) end end # Generate the bid ids - data['tickets'] = generate_bid_ids(entities[:event_id].id, tl_entities) + data["tickets"] = generate_bid_ids(entities[:event_id].id, tl_entities) - result['tickets'] = generated_ticket_entities(data['tickets'], result, entities) + result["tickets"] = generated_ticket_entities(data["tickets"], result, entities) - tktpur.tickets = result['tickets'] + tktpur.tickets = result["tickets"] trx.save! tktpur.save! @@ -150,43 +146,42 @@ def self.create(data, skip_notifications=false) subtrx.save! subtrx.subtransaction_payments.each(&:publish_created) end - - #tktpur.publish_created + + # tktpur.publish_created trx.publish_created # Create the activity rows for the tickets - InsertActivities.for_tickets(result['tickets'].map{|t| t.id}) + InsertActivities.for_tickets(result["tickets"].map { |t| t.id }) - ticket_ids = result['tickets'].map{|t| t.id} - charge_id = result['charge'] ? result['charge'].id : nil + ticket_ids = result["tickets"].map { |t| t.id } + charge_id = result["charge"] ? result["charge"].id : nil unless skip_notifications JobQueue.queue(JobTypes::TicketMailerReceiptAdminJob, ticket_ids) JobQueue.queue(JobTypes::TicketMailerFollowupJob, ticket_ids, charge_id) end - - return result - end + result + end # Generate a set of 'bid ids' (ids for each ticket scoped within the event) def self.generate_bid_ids(event_id, tickets) # Generate the bid ids last_bid_id = Ticket.where(event_id: event_id)&.pluck(:bid_id)&.max || 0 - tickets.zip(last_bid_id + 1 .. last_bid_id + tickets.count).map{|h, id| h.merge('bid_id' => id)} + tickets.zip(last_bid_id + 1..last_bid_id + tickets.count).map { |h, id| h.merge("bid_id" => id) } end - #not really needed but used for breaking into the unit test and getting the IDs + # not really needed but used for breaking into the unit test and getting the IDs def self.generated_ticket_entities(ticket_data, result, entities) - ticket_data.map{|ticket_request| + ticket_data.map { |ticket_request| t = Ticket.new - t.quantity = ticket_request['quantity'] - t.ticket_level = ticket_request['ticket_level_id'] + t.quantity = ticket_request["quantity"] + t.ticket_level = ticket_request["ticket_level_id"] t.event = entities[:event_id] t.supporter = entities[:supporter_id] - t.payment = result['payment'] - t.charge = result['charge'] - t.bid_id = ticket_request['bid_id'] + t.payment = result["payment"] + t.charge = result["charge"] + t.bid_id = ticket_request["bid_id"] t.event_discount = entities[:event_discount_id] t.save! t @@ -203,8 +198,8 @@ def self.validate_entities(entities, tl_entities) raise ParamValidation::ValidationError.new("Event #{entities[:event_id].id} is deleted", key: :event_id) end - #verify that enough tickets_available - tl_entities.each {|i| + # verify that enough tickets_available + tl_entities.each { |i| if i[:ticket_level_id].deleted raise ParamValidation::ValidationError.new("Ticket level #{i[:ticket_level_id].id} is deleted", key: :tickets) end @@ -230,38 +225,38 @@ def self.validate_entities(entities, tl_entities) end def self.get_ticket_level_entities(data) - data[:tickets].map{|i| + data[:tickets].map { |i| { - quantity: i[:quantity], - ticket_level_id: RetrieveActiveRecordItems.retrieve_from_keys(i, TicketLevel => :ticket_level_id)[:ticket_level_id] + quantity: i[:quantity], + ticket_level_id: RetrieveActiveRecordItems.retrieve_from_keys(i, TicketLevel => :ticket_level_id)[:ticket_level_id] } }.to_a end def self.create_payment(entities, gross_amount) p = Payment.new - p.gross_amount= gross_amount - p.nonprofit= entities[:nonprofit_id] - p.supporter= entities[:supporter_id] - p.refund_total= 0 + p.gross_amount = gross_amount + p.nonprofit = entities[:nonprofit_id] + p.supporter = entities[:supporter_id] + p.refund_total = 0 p.date = Time.current p.towards = entities[:event_id].name p.fee_total = 0 p.net_amount = gross_amount - p.kind= "OffsitePayment" + p.kind = "OffsitePayment" p.save! p end def self.create_offsite_payment(entities, gross_amount, data, payment) p = OffsitePayment.new - p.gross_amount= gross_amount - p.nonprofit= entities[:nonprofit_id] - p.supporter= entities[:supporter_id] - p.date= Time.current + p.gross_amount = gross_amount + p.nonprofit = entities[:nonprofit_id] + p.supporter = entities[:supporter_id] + p.date = Time.current p.payment = payment - p.kind = data['offsite_payment']['kind'] - p.check_number = data['offsite_payment']['check_number'] + p.kind = data["offsite_payment"]["kind"] + p.check_number = data["offsite_payment"]["check_number"] p.save! p end diff --git a/app/legacy_lib/insert_tracking.rb b/app/legacy_lib/insert_tracking.rb index dc5dc3ff6..0199739a2 100644 --- a/app/legacy_lib/insert_tracking.rb +++ b/app/legacy_lib/insert_tracking.rb @@ -3,18 +3,18 @@ module InsertTracking def self.create(params) result = {} - result['tracking'] = Qx.insert_into(:trackings) + result["tracking"] = Qx.insert_into(:trackings) .values({ utm_campaign: params[:utm_campaign], utm_content: params[:utm_content], utm_medium: params[:utm_medium], utm_source: params[:utm_source], donation_id: params[:donation_id] - }) + }) .timestamps - .returning('*') + .returning("*") .execute.first - { status: 200, json: result } + {status: 200, json: result} end end diff --git a/app/legacy_lib/interpolation_dictionary.rb b/app/legacy_lib/interpolation_dictionary.rb index 3c1c6e4d4..dd0ecf9e0 100644 --- a/app/legacy_lib/interpolation_dictionary.rb +++ b/app/legacy_lib/interpolation_dictionary.rb @@ -3,31 +3,31 @@ # InterpolationDictionary is a simple class for replacing braced variables, # like {{NAME}}, with a different value. We use this for email templates. class InterpolationDictionary - attr_reader :entries + attr_reader :entries - # pass in entries with defaults - def initialize(entries={}) - @entries = entries - end + # pass in entries with defaults + def initialize(entries = {}) + @entries = entries + end - def add_entry(entry_name, value) - if @entries.has_key?(entry_name) && full_sanitize(value).present? - @entries[entry_name] = full_sanitize(value) - end + def add_entry(entry_name, value) + if @entries.has_key?(entry_name) && full_sanitize(value).present? + @entries[entry_name] = full_sanitize(value) end + end - def interpolate(message) - result = Format::Interpolate.with_hash(message, @entries) - sanitize(result) if sanitize(result).present? - end + def interpolate(message) + result = Format::Interpolate.with_hash(message, @entries) + sanitize(result).presence + end - private + private - def full_sanitize(value) - ActionView::Base.full_sanitizer.sanitize(value) - end + def full_sanitize(value) + ActionView::Base.full_sanitizer.sanitize(value) + end - def sanitize(value) - ActionView::Base.safe_list_sanitizer.sanitize(value) - end -end \ No newline at end of file + def sanitize(value) + ActionView::Base.safe_list_sanitizer.sanitize(value) + end +end diff --git a/app/legacy_lib/job_queue.rb b/app/legacy_lib/job_queue.rb index bda8d6d29..ef2a2e805 100644 --- a/app/legacy_lib/job_queue.rb +++ b/app/legacy_lib/job_queue.rb @@ -3,4 +3,4 @@ module JobQueue def self.queue(klass, *args) Delayed::Job.enqueue klass.new(*args) end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_failed_gift_job.rb b/app/legacy_lib/job_types/admin_failed_gift_job.rb index 35a9b6fd0..3ea55a746 100644 --- a/app/legacy_lib/job_types/admin_failed_gift_job.rb +++ b/app/legacy_lib/job_types/admin_failed_gift_job.rb @@ -13,4 +13,4 @@ def perform AdminMailer.notify_failed_gift(@donation, @payment, @campaign_gift_option).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_dispute_created_job.rb b/app/legacy_lib/job_types/admin_notice_dispute_created_job.rb index 6dddb81e6..b5d7b3f4c 100644 --- a/app/legacy_lib/job_types/admin_notice_dispute_created_job.rb +++ b/app/legacy_lib/job_types/admin_notice_dispute_created_job.rb @@ -11,4 +11,4 @@ def perform DisputeMailer.created(dispute).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_dispute_funds_reinstated_job.rb b/app/legacy_lib/job_types/admin_notice_dispute_funds_reinstated_job.rb index 387b82d1e..63d1a52c2 100644 --- a/app/legacy_lib/job_types/admin_notice_dispute_funds_reinstated_job.rb +++ b/app/legacy_lib/job_types/admin_notice_dispute_funds_reinstated_job.rb @@ -11,4 +11,4 @@ def perform DisputeMailer.funds_reinstated(dispute).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_dispute_funds_withdrawn_job.rb b/app/legacy_lib/job_types/admin_notice_dispute_funds_withdrawn_job.rb index d0a7dc242..d3417fe6b 100644 --- a/app/legacy_lib/job_types/admin_notice_dispute_funds_withdrawn_job.rb +++ b/app/legacy_lib/job_types/admin_notice_dispute_funds_withdrawn_job.rb @@ -11,4 +11,4 @@ def perform DisputeMailer.funds_withdrawn(dispute).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_dispute_lost_job.rb b/app/legacy_lib/job_types/admin_notice_dispute_lost_job.rb index f3a1b748f..1edd1971f 100644 --- a/app/legacy_lib/job_types/admin_notice_dispute_lost_job.rb +++ b/app/legacy_lib/job_types/admin_notice_dispute_lost_job.rb @@ -11,4 +11,4 @@ def perform DisputeMailer.lost(dispute).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_dispute_updated_job.rb b/app/legacy_lib/job_types/admin_notice_dispute_updated_job.rb index c7e01582d..7d3c03439 100644 --- a/app/legacy_lib/job_types/admin_notice_dispute_updated_job.rb +++ b/app/legacy_lib/job_types/admin_notice_dispute_updated_job.rb @@ -11,4 +11,4 @@ def perform DisputeMailer.updated(dispute).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_dispute_won_job.rb b/app/legacy_lib/job_types/admin_notice_dispute_won_job.rb index 1bec960f1..9a1870dde 100644 --- a/app/legacy_lib/job_types/admin_notice_dispute_won_job.rb +++ b/app/legacy_lib/job_types/admin_notice_dispute_won_job.rb @@ -11,4 +11,4 @@ def perform DisputeMailer.won(dispute).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/admin_notice_job.rb b/app/legacy_lib/job_types/admin_notice_job.rb index a16720f16..abccd9e5c 100644 --- a/app/legacy_lib/job_types/admin_notice_job.rb +++ b/app/legacy_lib/job_types/admin_notice_job.rb @@ -11,4 +11,4 @@ def perform GenericMailer.admin_notice(@options).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/campaign_creation_followup_job.rb b/app/legacy_lib/job_types/campaign_creation_followup_job.rb index cb627e0a8..e7ca93231 100644 --- a/app/legacy_lib/job_types/campaign_creation_followup_job.rb +++ b/app/legacy_lib/job_types/campaign_creation_followup_job.rb @@ -11,4 +11,4 @@ def perform CampaignMailer.creation_followup(@campaign).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/campaign_updated_job.rb b/app/legacy_lib/job_types/campaign_updated_job.rb index 12fa1cfa1..2dcad0861 100644 --- a/app/legacy_lib/job_types/campaign_updated_job.rb +++ b/app/legacy_lib/job_types/campaign_updated_job.rb @@ -17,4 +17,4 @@ def perform end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/child_campaign_update_job.rb b/app/legacy_lib/job_types/child_campaign_update_job.rb index c32fc273a..3dbd576af 100644 --- a/app/legacy_lib/job_types/child_campaign_update_job.rb +++ b/app/legacy_lib/job_types/child_campaign_update_job.rb @@ -15,4 +15,4 @@ def perform child_campaign.update_from_parent! end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/dispute_created_job.rb b/app/legacy_lib/job_types/dispute_created_job.rb index 57412546b..8df44e70d 100644 --- a/app/legacy_lib/job_types/dispute_created_job.rb +++ b/app/legacy_lib/job_types/dispute_created_job.rb @@ -11,4 +11,4 @@ def perform JobQueue.queue(JobTypes::AdminNoticeDisputeCreatedJob, dispute) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/dispute_funds_reinstated_job.rb b/app/legacy_lib/job_types/dispute_funds_reinstated_job.rb index 1a6638360..a8d21e5c8 100644 --- a/app/legacy_lib/job_types/dispute_funds_reinstated_job.rb +++ b/app/legacy_lib/job_types/dispute_funds_reinstated_job.rb @@ -11,4 +11,4 @@ def perform JobQueue.queue(JobTypes::AdminNoticeDisputeFundsReinstatedJob, dispute) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/dispute_funds_withdrawn_job.rb b/app/legacy_lib/job_types/dispute_funds_withdrawn_job.rb index 2460fd6bd..15ad1c34f 100644 --- a/app/legacy_lib/job_types/dispute_funds_withdrawn_job.rb +++ b/app/legacy_lib/job_types/dispute_funds_withdrawn_job.rb @@ -11,4 +11,4 @@ def perform JobQueue.queue(JobTypes::AdminNoticeDisputeFundsWithdrawnJob, dispute) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/dispute_lost_job.rb b/app/legacy_lib/job_types/dispute_lost_job.rb index e109c3743..6fe68dd19 100644 --- a/app/legacy_lib/job_types/dispute_lost_job.rb +++ b/app/legacy_lib/job_types/dispute_lost_job.rb @@ -11,4 +11,4 @@ def perform JobQueue.queue(JobTypes::AdminNoticeDisputeLostJob, dispute) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/dispute_updated_job.rb b/app/legacy_lib/job_types/dispute_updated_job.rb index 30cb0af69..b5f987270 100644 --- a/app/legacy_lib/job_types/dispute_updated_job.rb +++ b/app/legacy_lib/job_types/dispute_updated_job.rb @@ -11,4 +11,4 @@ def perform JobQueue.queue(JobTypes::AdminNoticeDisputeUpdatedJob, dispute) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/dispute_won_job.rb b/app/legacy_lib/job_types/dispute_won_job.rb index fc898bebd..9161669d0 100644 --- a/app/legacy_lib/job_types/dispute_won_job.rb +++ b/app/legacy_lib/job_types/dispute_won_job.rb @@ -11,4 +11,4 @@ def perform JobQueue.queue(JobTypes::AdminNoticeDisputeWonJob, dispute) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/donation_payment_create_job.rb b/app/legacy_lib/job_types/donation_payment_create_job.rb index f40cccef6..a0087d131 100644 --- a/app/legacy_lib/job_types/donation_payment_create_job.rb +++ b/app/legacy_lib/job_types/donation_payment_create_job.rb @@ -3,7 +3,7 @@ module JobTypes class DonationPaymentCreateJob < GenericJob attr_reader :donation_id, :locale, :payment_id - def initialize(donation_id, payment_id, locale=I18n.locale) + def initialize(donation_id, payment_id, locale = I18n.locale) @donation_id = donation_id @payment_id = payment_id @locale = locale @@ -15,4 +15,4 @@ def perform JobQueue.queue(JobTypes::NonprofitFirstDonationPaymentJob, donation_id) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/donor_direct_debit_notification_job.rb b/app/legacy_lib/job_types/donor_direct_debit_notification_job.rb index dccf0fe00..dcc99e1a4 100644 --- a/app/legacy_lib/job_types/donor_direct_debit_notification_job.rb +++ b/app/legacy_lib/job_types/donor_direct_debit_notification_job.rb @@ -3,7 +3,7 @@ module JobTypes class DonorDirectDebitNotificationJob < EmailJob attr_reader :donation_id - def initialize(donation_id, locale=I18n.locale) + def initialize(donation_id, locale = I18n.locale) @donation_id = donation_id @locale = locale end @@ -12,4 +12,4 @@ def perform DonationMailer.donor_direct_debit_notification(@donation_id, @locale).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/donor_failed_recurring_donation_job.rb b/app/legacy_lib/job_types/donor_failed_recurring_donation_job.rb index 9b29bdd48..d0bede8a4 100644 --- a/app/legacy_lib/job_types/donor_failed_recurring_donation_job.rb +++ b/app/legacy_lib/job_types/donor_failed_recurring_donation_job.rb @@ -11,4 +11,4 @@ def perform DonationMailer.donor_failed_recurring_donation(@donation_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/donor_payment_notification_job.rb b/app/legacy_lib/job_types/donor_payment_notification_job.rb index 96990f8d3..72dbd371b 100644 --- a/app/legacy_lib/job_types/donor_payment_notification_job.rb +++ b/app/legacy_lib/job_types/donor_payment_notification_job.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class DonorPaymentNotificationJob < EmailJob - attr_reader :donation_id, :payment_id - def initialize(donation_id, payment_id, locale=I18n.locale) - @donation_id = donation_id - @payment_id = payment_id - @locale = locale - end + class DonorPaymentNotificationJob < EmailJob + attr_reader :donation_id, :payment_id + def initialize(donation_id, payment_id, locale = I18n.locale) + @donation_id = donation_id + @payment_id = payment_id + @locale = locale + end - def perform - DonationMailer.donor_payment_notification(@donation_id, @payment_id, @locale).deliver - end - end -end \ No newline at end of file + def perform + DonationMailer.donor_payment_notification(@donation_id, @payment_id, @locale).deliver + end + end +end diff --git a/app/legacy_lib/job_types/donor_recurring_donation_change_amount_job.rb b/app/legacy_lib/job_types/donor_recurring_donation_change_amount_job.rb index 4cb920fbf..5b36130de 100644 --- a/app/legacy_lib/job_types/donor_recurring_donation_change_amount_job.rb +++ b/app/legacy_lib/job_types/donor_recurring_donation_change_amount_job.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class DonorRecurringDonationChangeAmountJob < EmailJob - attr_reader :donation_id, :previous_amount - def initialize(donation_id, previous_amount=nil) - @donation_id = donation_id - @previous_amount = previous_amount - end + class DonorRecurringDonationChangeAmountJob < EmailJob + attr_reader :donation_id, :previous_amount + def initialize(donation_id, previous_amount = nil) + @donation_id = donation_id + @previous_amount = previous_amount + end - def perform - DonationMailer.donor_recurring_donation_change_amount(@donation_id, @previous_amount).deliver - end - end -end \ No newline at end of file + def perform + DonationMailer.donor_recurring_donation_change_amount(@donation_id, @previous_amount).deliver + end + end +end diff --git a/app/legacy_lib/job_types/donor_refund_notification_job.rb b/app/legacy_lib/job_types/donor_refund_notification_job.rb index 8cc4357e7..d70b9e103 100644 --- a/app/legacy_lib/job_types/donor_refund_notification_job.rb +++ b/app/legacy_lib/job_types/donor_refund_notification_job.rb @@ -1,13 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class DonorRefundNotificationJob < EmailJob - attr_reader :refund_id - def initialize(refund_id) - @refund_id = refund_id - end + class DonorRefundNotificationJob < EmailJob + attr_reader :refund_id + def initialize(refund_id) + @refund_id = refund_id + end - def perform - UserMailer.refund_receipt(@refund_id).deliver - end - end -end \ No newline at end of file + def perform + UserMailer.refund_receipt(@refund_id).deliver + end + end +end diff --git a/app/legacy_lib/job_types/email_job.rb b/app/legacy_lib/job_types/email_job.rb index 214f5da3a..9afb7236b 100644 --- a/app/legacy_lib/job_types/email_job.rb +++ b/app/legacy_lib/job_types/email_job.rb @@ -1,28 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class EmailJob - def perform - raise 'You need to override this' - end + class EmailJob + def perform + raise "You need to override this" + end - def max_attempts - MAX_EMAIL_JOB_ATTEMPTS || 1 - end + def max_attempts + MAX_EMAIL_JOB_ATTEMPTS || 1 + end - def destroy_failed_jobs? - false - end + def destroy_failed_jobs? + false + end - def error(job, exception) - Airbrake.notify(exception) - end + def error(job, exception) + Airbrake.notify(exception) + end - def reschedule_at(current_time, attempts) - current_time + attempts**(2.195); - end + def reschedule_at(current_time, attempts) + current_time + attempts**2.195 + end - def queue_name - 'email_queue' - end - end -end \ No newline at end of file + def queue_name + "email_queue" + end + end +end diff --git a/app/legacy_lib/job_types/event_creation_followup_job.rb b/app/legacy_lib/job_types/event_creation_followup_job.rb index 9141f3c2e..9be92907d 100644 --- a/app/legacy_lib/job_types/event_creation_followup_job.rb +++ b/app/legacy_lib/job_types/event_creation_followup_job.rb @@ -11,4 +11,4 @@ def perform EventMailer.creation_followup(@event).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_payment_completed_job.rb b/app/legacy_lib/job_types/export_payment_completed_job.rb index ad60f3922..fa570d657 100644 --- a/app/legacy_lib/job_types/export_payment_completed_job.rb +++ b/app/legacy_lib/job_types/export_payment_completed_job.rb @@ -11,4 +11,4 @@ def perform ExportMailer.export_payments_completed_notification(export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_payment_failed_job.rb b/app/legacy_lib/job_types/export_payment_failed_job.rb index bb1ffeaf1..0c471209a 100644 --- a/app/legacy_lib/job_types/export_payment_failed_job.rb +++ b/app/legacy_lib/job_types/export_payment_failed_job.rb @@ -11,4 +11,4 @@ def perform ExportMailer.export_payments_failed_notification(export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_recurring_donations_completed_job.rb b/app/legacy_lib/job_types/export_recurring_donations_completed_job.rb index 56f4ca1fa..6eed432b9 100644 --- a/app/legacy_lib/job_types/export_recurring_donations_completed_job.rb +++ b/app/legacy_lib/job_types/export_recurring_donations_completed_job.rb @@ -11,4 +11,4 @@ def perform ExportMailer.export_recurring_donations_completed_notification(@export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_recurring_donations_failed_job.rb b/app/legacy_lib/job_types/export_recurring_donations_failed_job.rb index dcfa69fbf..c90e51395 100644 --- a/app/legacy_lib/job_types/export_recurring_donations_failed_job.rb +++ b/app/legacy_lib/job_types/export_recurring_donations_failed_job.rb @@ -11,4 +11,4 @@ def perform ExportMailer.export_recurring_donations_failed_notification(@export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_supporter_notes_completed_job.rb b/app/legacy_lib/job_types/export_supporter_notes_completed_job.rb index 31ccd056a..0ca943d6b 100644 --- a/app/legacy_lib/job_types/export_supporter_notes_completed_job.rb +++ b/app/legacy_lib/job_types/export_supporter_notes_completed_job.rb @@ -11,4 +11,4 @@ def perform ExportMailer.export_supporter_notes_completed_notification(@export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_supporter_notes_failed_job.rb b/app/legacy_lib/job_types/export_supporter_notes_failed_job.rb index 40652dc14..6084a5463 100644 --- a/app/legacy_lib/job_types/export_supporter_notes_failed_job.rb +++ b/app/legacy_lib/job_types/export_supporter_notes_failed_job.rb @@ -11,4 +11,4 @@ def perform ExportMailer.export_supporter_notes_failed_notification(@export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_supporters_completed_job.rb b/app/legacy_lib/job_types/export_supporters_completed_job.rb index 7c9b09da3..968db456c 100644 --- a/app/legacy_lib/job_types/export_supporters_completed_job.rb +++ b/app/legacy_lib/job_types/export_supporters_completed_job.rb @@ -10,4 +10,4 @@ def perform ExportMailer.export_supporters_completed_notification(@export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/export_supporters_failed_job.rb b/app/legacy_lib/job_types/export_supporters_failed_job.rb index e7555f9e5..f661e5cce 100644 --- a/app/legacy_lib/job_types/export_supporters_failed_job.rb +++ b/app/legacy_lib/job_types/export_supporters_failed_job.rb @@ -10,4 +10,4 @@ def perform ExportMailer.export_supporters_failed_notification(@export).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/generic_job.rb b/app/legacy_lib/job_types/generic_job.rb index 0c90a5826..cdcf1d182 100644 --- a/app/legacy_lib/job_types/generic_job.rb +++ b/app/legacy_lib/job_types/generic_job.rb @@ -1,28 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class GenericJob - def perform - raise 'You need to override this' - end + class GenericJob + def perform + raise "You need to override this" + end - def max_attempts - MAX_GENERIC_JOB_ATTEMPTS || 1 - end + def max_attempts + MAX_GENERIC_JOB_ATTEMPTS || 1 + end - def destroy_failed_jobs? - false - end + def destroy_failed_jobs? + false + end - def error(job, exception) - Airbrake.notify(exception) - end + def error(job, exception) + Airbrake.notify(exception) + end - def reschedule_at(current_time, attempts) - current_time + attempts**(2.195); - end + def reschedule_at(current_time, attempts) + current_time + attempts**2.195 + end - def queue_name - 'generic_queue' - end - end -end \ No newline at end of file + def queue_name + "generic_queue" + end + end +end diff --git a/app/legacy_lib/job_types/generic_mail_job.rb b/app/legacy_lib/job_types/generic_mail_job.rb index 1a7738a52..ed9fd82a8 100644 --- a/app/legacy_lib/job_types/generic_mail_job.rb +++ b/app/legacy_lib/job_types/generic_mail_job.rb @@ -16,4 +16,4 @@ def perform GenericMailer.generic_mail(@from_email, @from_name, @message, @subject, @to_email, @to_name).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/import_complete_notification_job.rb b/app/legacy_lib/job_types/import_complete_notification_job.rb index fca866b7f..6bb84ff09 100644 --- a/app/legacy_lib/job_types/import_complete_notification_job.rb +++ b/app/legacy_lib/job_types/import_complete_notification_job.rb @@ -11,4 +11,4 @@ def perform ImportMailer.import_completed_notification(@import_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_admin_existing_invite_job.rb b/app/legacy_lib/job_types/nonprofit_admin_existing_invite_job.rb index 2f2a3322b..e429d7e88 100644 --- a/app/legacy_lib/job_types/nonprofit_admin_existing_invite_job.rb +++ b/app/legacy_lib/job_types/nonprofit_admin_existing_invite_job.rb @@ -11,4 +11,4 @@ def perform NonprofitAdminMailer.existing_invite(@role).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_admin_new_invite_job.rb b/app/legacy_lib/job_types/nonprofit_admin_new_invite_job.rb index c0d03deab..693034ec6 100644 --- a/app/legacy_lib/job_types/nonprofit_admin_new_invite_job.rb +++ b/app/legacy_lib/job_types/nonprofit_admin_new_invite_job.rb @@ -12,4 +12,4 @@ def perform NonprofitAdminMailer.new_invite(@role, @raw_token).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_admin_supporter_fundraiser_job.rb b/app/legacy_lib/job_types/nonprofit_admin_supporter_fundraiser_job.rb index 031fd9302..00309aafd 100644 --- a/app/legacy_lib/job_types/nonprofit_admin_supporter_fundraiser_job.rb +++ b/app/legacy_lib/job_types/nonprofit_admin_supporter_fundraiser_job.rb @@ -11,4 +11,4 @@ def perform NonprofitAdminMailer.supporter_fundraiser(@event_or_campaign).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_create_job.rb b/app/legacy_lib/job_types/nonprofit_create_job.rb index d046d4788..4e366aabf 100644 --- a/app/legacy_lib/job_types/nonprofit_create_job.rb +++ b/app/legacy_lib/job_types/nonprofit_create_job.rb @@ -11,4 +11,4 @@ def perform Delayed::Job.enqueue JobTypes::NonprofitWelcomeJob.new nonprofit_id end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_failed_recurring_donation_job.rb b/app/legacy_lib/job_types/nonprofit_failed_recurring_donation_job.rb index bb3f2f534..ee14b470c 100644 --- a/app/legacy_lib/job_types/nonprofit_failed_recurring_donation_job.rb +++ b/app/legacy_lib/job_types/nonprofit_failed_recurring_donation_job.rb @@ -11,4 +11,4 @@ def perform DonationMailer.nonprofit_failed_recurring_donation(@donation_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_first_charge_email_job.rb b/app/legacy_lib/job_types/nonprofit_first_charge_email_job.rb index ef74e2945..08771fbf5 100644 --- a/app/legacy_lib/job_types/nonprofit_first_charge_email_job.rb +++ b/app/legacy_lib/job_types/nonprofit_first_charge_email_job.rb @@ -11,4 +11,4 @@ def perform NonprofitMailer.first_charge_email(nonprofit_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_first_donation_payment_job.rb b/app/legacy_lib/job_types/nonprofit_first_donation_payment_job.rb index 83c926119..6bb5b501d 100644 --- a/app/legacy_lib/job_types/nonprofit_first_donation_payment_job.rb +++ b/app/legacy_lib/job_types/nonprofit_first_donation_payment_job.rb @@ -12,7 +12,7 @@ def perform nonprofit = d.nonprofit if nonprofit && d.charges.any? np_infos = nonprofit.miscellaneous_np_info || nonprofit.create_miscellaneous_np_info - np_infos.with_lock("FOR UPDATE") do + np_infos.with_lock("FOR UPDATE") do if !np_infos.first_charge_email_sent JobQueue.queue(JobTypes::NonprofitFirstChargeEmailJob, nonprofit.id) np_infos.first_charge_email_sent = true @@ -22,4 +22,4 @@ def perform end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_first_ticket_payment_job.rb b/app/legacy_lib/job_types/nonprofit_first_ticket_payment_job.rb index 9c2c7a637..0030baf2d 100644 --- a/app/legacy_lib/job_types/nonprofit_first_ticket_payment_job.rb +++ b/app/legacy_lib/job_types/nonprofit_first_ticket_payment_job.rb @@ -22,4 +22,4 @@ def perform end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_new_bank_account_job.rb b/app/legacy_lib/job_types/nonprofit_new_bank_account_job.rb index b7688f7c5..89333a3b7 100644 --- a/app/legacy_lib/job_types/nonprofit_new_bank_account_job.rb +++ b/app/legacy_lib/job_types/nonprofit_new_bank_account_job.rb @@ -11,4 +11,4 @@ def perform NonprofitMailer.new_bank_account_notification(@ba).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_payment_notification_job.rb b/app/legacy_lib/job_types/nonprofit_payment_notification_job.rb index b57c91a5f..2c8569cd4 100644 --- a/app/legacy_lib/job_types/nonprofit_payment_notification_job.rb +++ b/app/legacy_lib/job_types/nonprofit_payment_notification_job.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class NonprofitPaymentNotificationJob < EmailJob - attr_reader :donation_id, :user_id, :payment_id - def initialize(donation_id, payment_id, user_id=nil) - @donation_id = donation_id - @payment_id = payment_id - @user_id = user_id - end + class NonprofitPaymentNotificationJob < EmailJob + attr_reader :donation_id, :user_id, :payment_id + def initialize(donation_id, payment_id, user_id = nil) + @donation_id = donation_id + @payment_id = payment_id + @user_id = user_id + end - def perform - DonationMailer.nonprofit_payment_notification(@donation_id, @payment_id, @user_id).deliver - end - end -end \ No newline at end of file + def perform + DonationMailer.nonprofit_payment_notification(@donation_id, @payment_id, @user_id).deliver + end + end +end diff --git a/app/legacy_lib/job_types/nonprofit_pending_payout_job.rb b/app/legacy_lib/job_types/nonprofit_pending_payout_job.rb index 662e3f350..5ee9e7166 100644 --- a/app/legacy_lib/job_types/nonprofit_pending_payout_job.rb +++ b/app/legacy_lib/job_types/nonprofit_pending_payout_job.rb @@ -11,4 +11,4 @@ def perform NonprofitMailer.pending_payout_notification(@payout_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_recurring_donation_cancellation_job.rb b/app/legacy_lib/job_types/nonprofit_recurring_donation_cancellation_job.rb index 0f0513d60..640b642ce 100644 --- a/app/legacy_lib/job_types/nonprofit_recurring_donation_cancellation_job.rb +++ b/app/legacy_lib/job_types/nonprofit_recurring_donation_cancellation_job.rb @@ -11,4 +11,4 @@ def perform DonationMailer.nonprofit_recurring_donation_cancellation(@donation_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_recurring_donation_change_amount_job.rb b/app/legacy_lib/job_types/nonprofit_recurring_donation_change_amount_job.rb index c1209e409..e21a31e3a 100644 --- a/app/legacy_lib/job_types/nonprofit_recurring_donation_change_amount_job.rb +++ b/app/legacy_lib/job_types/nonprofit_recurring_donation_change_amount_job.rb @@ -3,7 +3,7 @@ module JobTypes class NonprofitRecurringDonationChangeAmountJob < EmailJob attr_reader :donation_id, :previous_amount - def initialize(donation_id, previous_amount=nil) + def initialize(donation_id, previous_amount = nil) @donation_id = donation_id @previous_amount = previous_amount end @@ -12,4 +12,4 @@ def perform DonationMailer.nonprofit_recurring_donation_change_amount(@donation_id, @previous_amount).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/nonprofit_refund_notification_job.rb b/app/legacy_lib/job_types/nonprofit_refund_notification_job.rb index 8678de7c6..a4fc241d0 100644 --- a/app/legacy_lib/job_types/nonprofit_refund_notification_job.rb +++ b/app/legacy_lib/job_types/nonprofit_refund_notification_job.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module JobTypes - class NonprofitRefundNotificationJob < EmailJob - attr_reader :refund_id, :user_id - def initialize(refund_id, user_id=nil) - @refund_id = refund_id - @user_id = user_id - end + class NonprofitRefundNotificationJob < EmailJob + attr_reader :refund_id, :user_id + def initialize(refund_id, user_id = nil) + @refund_id = refund_id + @user_id = user_id + end - def perform - NonprofitMailer.refund_notification(@refund_id, @user_id).deliver - end - end -end \ No newline at end of file + def perform + NonprofitMailer.refund_notification(@refund_id, @user_id).deliver + end + end +end diff --git a/app/legacy_lib/job_types/nonprofit_welcome_job.rb b/app/legacy_lib/job_types/nonprofit_welcome_job.rb index dd0fb773c..7e481cec7 100644 --- a/app/legacy_lib/job_types/nonprofit_welcome_job.rb +++ b/app/legacy_lib/job_types/nonprofit_welcome_job.rb @@ -11,4 +11,4 @@ def perform NonprofitMailer.welcome(@nonprofit_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/refund_created_job.rb b/app/legacy_lib/job_types/refund_created_job.rb index 6d39942f0..539fbc06c 100644 --- a/app/legacy_lib/job_types/refund_created_job.rb +++ b/app/legacy_lib/job_types/refund_created_job.rb @@ -12,4 +12,4 @@ def perform JobQueue.queue JobTypes::NonprofitRefundNotificationJob, refund.id end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/ticket_mailer_followup_job.rb b/app/legacy_lib/job_types/ticket_mailer_followup_job.rb index e7749058c..c04e97e71 100644 --- a/app/legacy_lib/job_types/ticket_mailer_followup_job.rb +++ b/app/legacy_lib/job_types/ticket_mailer_followup_job.rb @@ -12,4 +12,4 @@ def perform TicketMailer.followup(@ticket_ids, @charge_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/job_types/ticket_mailer_receipt_admin_job.rb b/app/legacy_lib/job_types/ticket_mailer_receipt_admin_job.rb index b65c2fe2e..df7a289dc 100644 --- a/app/legacy_lib/job_types/ticket_mailer_receipt_admin_job.rb +++ b/app/legacy_lib/job_types/ticket_mailer_receipt_admin_job.rb @@ -3,7 +3,7 @@ module JobTypes class TicketMailerReceiptAdminJob < EmailJob attr_reader :ticket_ids - def initialize(ticket_ids, user_id=nil) + def initialize(ticket_ids, user_id = nil) @ticket_ids = ticket_ids @user_id = user_id end @@ -12,4 +12,4 @@ def perform TicketMailer.receipt_admin(@ticket_ids, @user_id).deliver end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/json_resp.rb b/app/legacy_lib/json_resp.rb index f4d323f0f..ef362a8ca 100644 --- a/app/legacy_lib/json_resp.rb +++ b/app/legacy_lib/json_resp.rb @@ -9,7 +9,6 @@ # * Respond with proper codes and error messages for everything class JsonResp - attr_accessor :errors def initialize(params, &block) @@ -17,7 +16,6 @@ def initialize(params, &block) validation = JsonResp::Validation.new(params) validation.instance_exec(params, &block) @errors = validation.errors - return self end def when_valid(&block) @@ -29,24 +27,21 @@ def when_valid(&block) puts e puts e.backtrace.first(10) end - return @response + @response end - # Validation of a set of request parameters class Validation - attr_accessor :errors, :params def initialize(params) @params = params @errors = [] - return self end def requires(*keys) - @errors.concat keys.select{|k| @params[k].blank? }.map{|k| "#{k} required"} - return Param.new(keys, @errors, @params) + @errors.concat keys.select { |k| @params[k].blank? }.map { |k| "#{k} required" } + Param.new(keys, @errors, @params) end def requires_either(key1, key2) @@ -54,16 +49,15 @@ def requires_either(key1, key2) if @params[key1].blank? && @params[key2].blank? @errors << error_message else - @errors.concat [key1, key2].select{|k| @params[k].blank? }.map{|k| "#{k} required"} + @errors.concat [key1, key2].select { |k| @params[k].blank? }.map { |k| "#{k} required" } end - return Param.new([key1, key2], @errors, @params) + Param.new([key1, key2], @errors, @params) end def optional(*keys) - keys_to_check = keys.select{|k| @params[k].present?} - return Param.new(keys_to_check, @errors, @params) + keys_to_check = keys.select { |k| @params[k].present? } + Param.new(keys_to_check, @errors, @params) end - end class Param @@ -74,67 +68,66 @@ class Param attr_accessor :keys, :errors, :params def initialize(keys, errors, params) - @keys = keys.reject{|k| params[k].nil? } + @keys = keys.reject { |k| params[k].nil? } @errors = errors @params = params end def as_string - @errors.concat @keys.reject{|k| @params[k].is_a?(String)}.map{|k| "#{k} must be a string"} - return self + @errors.concat @keys.reject { |k| @params[k].is_a?(String) }.map { |k| "#{k} must be a string" } + self end def as_int @errors.concat @keys - .reject{|k| @params[k].is_a?(Integer) || @params[k].to_i.to_s == @params[k]} - .map{|k| "#{k} must be an integer"} - return self + .reject { |k| @params[k].is_a?(Integer) || @params[k].to_i.to_s == @params[k] } + .map { |k| "#{k} must be an integer" } + self end def with_format(regex) - @errors.concat @keys.reject{|k| @params[k] =~ regex}.map{|k| "#{k} must match: #{regex}"} - return self + @errors.concat @keys.reject { |k| @params[k] =~ regex }.map { |k| "#{k} must match: #{regex}" } + self end def one_of(*vals) - @errors.concat @keys.reject{|k| vals.include?(@params[k])}.map{|k| "#{k} must be one of: #{vals.join(", ")}"} - return self + @errors.concat @keys.reject { |k| vals.include?(@params[k]) }.map { |k| "#{k} must be one of: #{vals.join(", ")}" } + self end def nested(&block) - @errors.concat @keys.map{|k| Validation.new(@params[k]).instance_exec(@params, &block).errors}.flatten - return self + @errors.concat @keys.map { |k| Validation.new(@params[k]).instance_exec(@params, &block).errors }.flatten + self end def as_array - @errors.concat @keys.reject{|k| @params[k].is_a?(Array)}.map{|k| "#{k} must be an array"} + @errors.concat @keys.reject { |k| @params[k].is_a?(Array) }.map { |k| "#{k} must be an array" } end def array_of(&block) - @errors.concat @keys.reject{|k| @params[k].is_a?(Array)}.map{|k| "#{k} must be an array"} - @errors.concat @keys.map{|k| @params[k].map{|h| Validation.new(h).instance_exec(@params, &block).errors}}.flatten - return self + @errors.concat @keys.reject { |k| @params[k].is_a?(Array) }.map { |k| "#{k} must be an array" } + @errors.concat @keys.map { |k| @params[k].map { |h| Validation.new(h).instance_exec(@params, &block).errors } }.flatten + self end def as_date - with_format /\d\d\d\d-\d\d-\d\d/ - @errors.concat @keys.map{|k| [k].concat @params[k].split('-').map(&:to_i)} - .reject{|key, year, month, day| year.present? && year > 1000 && year < 3000 && month.present? && month > 0 && month < 13 && day.present? && day > 0 && day < 32} - .map{|k, _,_,_| "#{k} must be a valid date"} + with_format(/\d\d\d\d-\d\d-\d\d/) + @errors.concat @keys.map { |k| [k].concat @params[k].split("-").map(&:to_i) } + .reject { |key, year, month, day| year.present? && year > 1000 && year < 3000 && month.present? && month > 0 && month < 13 && day.present? && day > 0 && day < 32 } + .map { |k, _, _, _| "#{k} must be a valid date" } end def min(n) - @errors.concat @keys.reject{|k| @params[k].to_i >= n}.map{|k| "#{k} must be at least #{n}"} - return self + @errors.concat @keys.reject { |k| @params[k].to_i >= n }.map { |k| "#{k} must be at least #{n}" } + self end def max(n) - @errors.concat @keys.reject{|k| @params[k].to_i <= n}.map{|k| "#{k} must be less than #{n + 1}"} - return self + @errors.concat @keys.reject { |k| @params[k].to_i <= n }.map { |k| "#{k} must be less than #{n + 1}" } + self end # TODO min_len, max_len, as_float, as_currency, as_time, as_datetime # TODO return err resp on unrecognized params - end end diff --git a/app/legacy_lib/mailchimp.rb b/app/legacy_lib/mailchimp.rb index ebc34aaf2..d887edd2e 100644 --- a/app/legacy_lib/mailchimp.rb +++ b/app/legacy_lib/mailchimp.rb @@ -1,66 +1,65 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'httparty' -require 'digest/md5' - +require "httparty" +require "digest/md5" module Mailchimp - include HTTParty - format :json + include HTTParty + format :json logger Rails.logger, :info, :mailchimp def self.base_uri(key) dc = get_datacenter(key) - return "https://#{dc}.api.mailchimp.com/3.0" + "https://#{dc}.api.mailchimp.com/3.0" end - # Run the configuration from an initializer - # data: {:api_key => String} - def self.config(hash) + # Run the configuration from an initializer + # data: {:api_key => String} + def self.config(hash) @apikey = hash[:api_key] - @options = { - :headers => { - 'Content-Type' => 'application/json', - 'Accept' => 'application/json' - } - } - @body = { - :apikey => hash[:api_key] - } - end + @options = { + headers: { + "Content-Type" => "application/json", + "Accept" => "application/json" + } + } + @body = { + apikey: hash[:api_key] + } + end # Given a nonprofit mailchimp oauth2 key, return its current datacenter def self.get_datacenter(key) - metadata = HTTParty.get('https://login.mailchimp.com/oauth2/metadata', { - headers: { - 'User-Agent' => 'oauth2-draft-v10', - 'Host' => 'login.mailchimp.com', - 'Accept' => 'application/json', - 'Authorization' => "OAuth #{key}", - 'apikey' => @apikey + metadata = HTTParty.get("https://login.mailchimp.com/oauth2/metadata", { + headers: { + "User-Agent" => "oauth2-draft-v10", + "Host" => "login.mailchimp.com", + "Accept" => "application/json", + "Authorization" => "OAuth #{key}", + "apikey" => @apikey }, logger: Rails.logger, log_level: :info, log_format: :mailchimp }) - return metadata['dc'] + metadata["dc"] end - def self.signup supporter, mailchimp_list - body_hash = @body.merge(create_subscribe_body(supporter)) - put(mailchimp_list.list_members_url, @options.merge(:body => body_hash.to_json)) + def self.signup supporter, mailchimp_list + body_hash = @body.merge(create_subscribe_body(supporter)) + put(mailchimp_list.list_members_url, @options.merge(body: body_hash.to_json)) end def self.signup_nonprofit_user(drip_email_list, nonprofit, user) body_hash = @body.merge(create_nonprofit_user_subscribe_body(nonprofit, user)) uri = "https://us5.api.mailchimp.com/3.0" # hardcoded for us - put(uri + "/" + generate_list_member_path(drip_email_list.list_members_path, user.email), @options.merge(:body => body_hash.to_json, - basic_auth: {username: "user", password: @apikey})) - end + put(uri + "/" + generate_list_member_path(drip_email_list.list_members_path, user.email), @options.merge(body: body_hash.to_json, + basic_auth: {username: "user", password: @apikey})) + end def self.get_mailchimp_token(npo_id) - mailchimp_token = QueryNonprofitKeys.get_key(npo_id, 'mailchimp_token') + mailchimp_token = QueryNonprofitKeys.get_key(npo_id, "mailchimp_token") throw RuntimeError.new("No Mailchimp connection for this nonprofit: #{npo_id}") if mailchimp_token.nil? - return mailchimp_token + mailchimp_token end # Get all lists owned by the nonprofit represented by the mailchimp token @@ -68,16 +67,15 @@ def get_all_lists(mailchimp_token) uri = base_uri(mailchimp_token) puts "URI #{uri}" puts "KEY #{mailchimp_token}" - get(uri+'/lists', { - basic_auth: {username: '', password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'}, - } - ) + get(uri + "/lists", { + basic_auth: {username: "", password: mailchimp_token}, + headers: {"Content-Type" => "application/json"} + }) end # Given a nonprofit id and a list of tag master ids that they make into email lists, # create those email lists on mailchimp and return an array of hashes of mailchimp list ids, names, and tag_master_id - def self.create_mailchimp_lists(npo_id, tag_master_ids) + def self.create_mailchimp_lists(npo_id, tag_master_ids) mailchimp_token = get_mailchimp_token(npo_id) uri = base_uri(mailchimp_token) puts "URI #{uri}" @@ -92,60 +90,60 @@ def self.create_mailchimp_lists(npo_id, tag_master_ids) .execute tags.map do |h| - list = post(uri+'/lists', { - basic_auth: {username: '', password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'}, + list = post(uri + "/lists", { + basic_auth: {username: "", password: mailchimp_token}, + headers: {"Content-Type" => "application/json"}, body: { - name: 'CommitChange-'+h['tag_name'], + name: "CommitChange-" + h["tag_name"], contact: { - company: npo['name'], - address1: npo['address'] || '', - city: npo['city'] || '', - state: npo['state_code'] || '', - zip: npo['zip_code'] || '', - country: 'US', - phone: npo['phone'] || '' - }, - permission_reminder: 'You are a registered supporter of our nonprofit.', - campaign_defaults: { - from_name: npo['name'] || '', - from_email: npo['email'].blank? ? "support@commitchange.com" : npo['email'], - subject: "Enter your subject here...", - language: 'en' - }, - email_type_option: false, - visibility: 'prv' + company: npo["name"], + address1: npo["address"] || "", + city: npo["city"] || "", + state: npo["state_code"] || "", + zip: npo["zip_code"] || "", + country: "US", + phone: npo["phone"] || "" + }, + permission_reminder: "You are a registered supporter of our nonprofit.", + campaign_defaults: { + from_name: npo["name"] || "", + from_email: npo["email"].presence || "support@commitchange.com", + subject: "Enter your subject here...", + language: "en" + }, + email_type_option: false, + visibility: "prv" }.to_json }) if list.code != 200 raise Exception.new("Failed to create list: #{list}") end - {id: list['id'], name: list['name'], tag_master_id: h['id']} + {id: list["id"], name: list["name"], tag_master_id: h["id"]} end end # Given a nonprofit id and post_data, which is an array of batch operation hashes OR MailchimpBatchOperation objects # See here: http://developer.mailchimp.com/documentation/mailchimp/guides/how-to-use-batch-operations/ - # Perform all the batch operations and return a status report + # Perform all the batch operations and return a status report def self.perform_batch_operations(npo_id, post_data) post_data = post_data.map(&:to_h).select(&:present?) # the select removes any nil items return if post_data.empty? mailchimp_token = get_mailchimp_token(npo_id) uri = base_uri(mailchimp_token) - batch_job_id = post(uri + '/batches', { + batch_job_id = post(uri + "/batches", { basic_auth: {username: @username, password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'}, + headers: {"Content-Type" => "application/json"}, body: {operations: post_data}.to_json - })['id'] + })["id"] check_batch_status(npo_id, batch_job_id) end def self.check_batch_status(npo_id, batch_job_id) mailchimp_token = get_mailchimp_token(npo_id) uri = base_uri(mailchimp_token) - batch_status = get(uri+'/batches/'+batch_job_id, { + get(uri + "/batches/" + batch_job_id, { basic_auth: {username: @username, password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'} + headers: {"Content-Type" => "application/json"} }) end @@ -164,117 +162,116 @@ def self.sync_supporters_to_list_from_tag_joins(npo_id, supporter_ids, tag_data) to_remove = get_mailchimp_list_ids(tag_data.unselected.to_tag_master_ids) return if to_add.empty? && to_remove.empty? - bulk_post = emails.map{|em| to_add.map{|ml_id| {method: 'POST', path: "lists/#{ml_id}/members", body: {email_address: em, status: 'subscribed'}.to_json}}}.flatten - bulk_delete = emails.map{|em| to_remove.map{|ml_id| {method: 'DELETE', path: "lists/#{ml_id}/members/#{Digest::MD5.hexdigest(em.downcase).to_s}"}}}.flatten + bulk_post = emails.map { |em| to_add.map { |ml_id| {method: "POST", path: "lists/#{ml_id}/members", body: {email_address: em, status: "subscribed"}.to_json} } }.flatten + bulk_delete = emails.map { |em| to_remove.map { |ml_id| {method: "DELETE", path: "lists/#{ml_id}/members/#{Digest::MD5.hexdigest(em.downcase)}"} } }.flatten perform_batch_operations(npo_id, bulk_post.concat(bulk_delete)) end - def self.get_emails_for_supporter_ids(npo_id, supporters_ids=[]) - Nonprofit.find(npo_id).supporters.where('id in (?)', supporters_ids).pluck(:email).select(&:present?) + def self.get_emails_for_supporter_ids(npo_id, supporters_ids = []) + Nonprofit.find(npo_id).supporters.where("id in (?)", supporters_ids).pluck(:email).select(&:present?) end def self.get_mailchimp_list_ids(tag_master_ids) return [] if tag_master_ids.empty? - to_insert_data = Qx.select("email_lists.mailchimp_list_id") + Qx.select("email_lists.mailchimp_list_id") .from(:tag_masters) .where("tag_masters.id IN ($ids)", ids: tag_master_ids) .join("email_lists", "email_lists.tag_master_id=tag_masters.id") - .execute.map{|h| h['mailchimp_list_id']} + .execute.map { |h| h["mailchimp_list_id"] } end - # @param [Nonprofit] nonprofit # @param [Boolean] delete_from_mailchimp do you want to delete extra items on mailchimp, defaults to false - def self.hard_sync_lists(nonprofit, delete_from_mailchimp=false) + def self.hard_sync_lists(nonprofit, delete_from_mailchimp = false) return if !nonprofit nonprofit.tag_masters.not_deleted.each do |i| - if (i.email_list) + if i.email_list hard_sync_list(i.email_list, delete_from_mailchimp) end end end def self.sync_nonprofit_users - User.nonprofit_personnel.find_each do |np_user| - MailchimpNonprofitUserAddJob.perform_later(np_user, np_user.roles.nonprofit_personnel.first.host ) - end - end + User.nonprofit_personnel.find_each do |np_user| + MailchimpNonprofitUserAddJob.perform_later(np_user, np_user.roles.nonprofit_personnel.first.host) + end + end # @param [EmailList] email_list # @param [Boolean] delete_from_mailchimp do you want to delete extra items on mailchimp, defaults to false - def self.hard_sync_list(email_list, delete_from_mailchimp=false) + def self.hard_sync_list(email_list, delete_from_mailchimp = false) ops = generate_batch_ops_for_hard_sync(email_list, delete_from_mailchimp) perform_batch_operations(email_list.nonprofit.id, ops) - end # @param [Boolean] delete_from_mailchimp do you want to delete extra items on mailchimp, defaults to false - def self.generate_batch_ops_for_hard_sync(email_list, delete_from_mailchimp=false) - #get the subscribers from mailchimp + def self.generate_batch_ops_for_hard_sync(email_list, delete_from_mailchimp = false) + # get the subscribers from mailchimp mailchimp_subscribers = get_list_mailchimp_subscribers(email_list) - #get our subscribers - our_supporters = email_list.tag_master.tag_joins.map{|i| i.supporter} + # get our subscribers + our_supporters = email_list.tag_master.tag_joins.map { |i| i.supporter } - #split them as follows: + # split them as follows: # on both lists, on our list, on the mailchimp list - in_both, in_mailchimp_only = mailchimp_subscribers.partition do |mc_sub| - our_supporters.any?{|s| s.email.downcase == mc_sub[:email_address].downcase} + _, in_mailchimp_only = mailchimp_subscribers.partition do |mc_sub| + our_supporters.any? { |s| s.email.downcase == mc_sub[:email_address].downcase } end - + _, in_our_side_only = our_supporters.partition do |s| - mailchimp_subscribers.any?{|mc_sub| s.email.downcase == mc_sub[:email_address].downcase} + mailchimp_subscribers.any? { |mc_sub| s.email.downcase == mc_sub[:email_address].downcase } end # if on our list, add to mailchimp - output = in_our_side_only.map{|i| - {method: 'POST', path: "lists/#{email_list.mailchimp_list_id}/members", body: create_subscribe_body(i).to_json} + output = in_our_side_only.map { |i| + {method: "POST", path: "lists/#{email_list.mailchimp_list_id}/members", body: create_subscribe_body(i).to_json} } if delete_from_mailchimp # if on mailchimp list, delete from mailchimp - output = output.concat(in_mailchimp_only.map{|i| {method: 'DELETE', path: "lists/#{email_list.mailchimp_list_id}/members/#{i[:id]}"}}) + output = output.concat(in_mailchimp_only.map { |i| {method: "DELETE", path: "lists/#{email_list.mailchimp_list_id}/members/#{i[:id]}"} }) end - return output + output end def self.get_list_mailchimp_subscribers(email_list) mailchimp_token = get_mailchimp_token(email_list.tag_master.nonprofit.id) uri = base_uri(mailchimp_token) - result = get(uri + "/lists/#{email_list.mailchimp_list_id}/members?count=1000000000", { + result = get(uri + "/lists/#{email_list.mailchimp_list_id}/members?count=1000000000", { basic_auth: {username: @username, password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'}}) - members = result['members'].map do |i| - {id: i['id'], email_address: i['email_address']} - end.to_a + headers: {"Content-Type" => "application/json"} + }) + result["members"].map do |i| + {id: i["id"], email_address: i["email_address"]} + end.to_a end def self.get_email_lists(nonprofit) mailchimp_token = get_mailchimp_token(nonprofit.id) uri = base_uri(mailchimp_token) - result = get(uri + "/lists?count=1000000000", { + result = get(uri + "/lists?count=1000000000", { basic_auth: {username: @username, password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'}}) - result['lists'] - + headers: {"Content-Type" => "application/json"} + }) + result["lists"] end def self.get_list(nonprofit, list_id) mailchimp_token = get_mailchimp_token(nonprofit.id) uri = base_uri(mailchimp_token) - result = get(uri + "/lists/#{list_id}", { - basic_auth: {username: @username, password: mailchimp_token}, - headers: {'Content-Type' => 'application/json'}}) - result + get(uri + "/lists/#{list_id}", { + basic_auth: {username: @username, password: mailchimp_token}, + headers: {"Content-Type" => "application/json"} + }) end - def self.create_nonprofit_user_subscribe_body(nonprofit,user) - JSON::parse(ApplicationController.render 'mailchimp/nonprofit_user_subscribe', assigns: {nonprofit: nonprofit, user: user }) - end + def self.create_nonprofit_user_subscribe_body(nonprofit, user) + JSON.parse(ApplicationController.render("mailchimp/nonprofit_user_subscribe", assigns: {nonprofit: nonprofit, user: user})) + end def self.create_subscribe_body(supporter) - JSON::parse(ApplicationController.render 'mailchimp/list', assigns: {supporter: supporter}) + JSON.parse(ApplicationController.render("mailchimp/list", assigns: {supporter: supporter})) end def self.generate_list_member_path(list_members_path, email) diff --git a/app/legacy_lib/maintain_dedications.rb b/app/legacy_lib/maintain_dedications.rb index 593352076..180f6bf00 100644 --- a/app/legacy_lib/maintain_dedications.rb +++ b/app/legacy_lib/maintain_dedications.rb @@ -1,44 +1,43 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module MaintainDedications def self.retrieve_json_dedications - return Qx.select('id', 'dedication').from(:donations) - .where("is_valid_json(dedication)").ex - + Qx.select("id", "dedication").from(:donations) + .where("is_valid_json(dedication)").ex end - def self.retrieve_non_json_dedications(include_blank=false) - temp = Qx.select('id', 'dedication').from(:donations) + def self.retrieve_non_json_dedications(include_blank = false) + temp = Qx.select("id", "dedication").from(:donations) temp = temp.where("dedication IS NOT NULL AND dedication != ''") unless include_blank temp = temp.and_where("NOT is_valid_json(dedication)") - return temp.ex + temp.ex end def self.create_json_dedications_from_plain_text(dedications) dedications.map do |i| - output = {id: i['id']} - if i['dedication'] =~ /(((in (loving )?)?memory of|in memorium)\:? )(.+)/i || i['dedication'] =~ /(IMO )(.+)/ - output[:dedication] = JSON.generate({type: 'memory', note: $+ }) - elsif i['dedication'] =~ /((in honor of|honor of)\:? )(.+)/i || i['dedication'] =~ /(IHO )(.+)/ - output[:dedication] = JSON.generate({type: 'honor', note: $+ }) + output = {id: i["id"]} + output[:dedication] = if i["dedication"] =~ /(((in (loving )?)?memory of|in memorium):? )(.+)/i || i["dedication"] =~ /(IMO )(.+)/ + JSON.generate({type: "memory", note: $+}) + elsif i["dedication"] =~ /((in honor of|honor of):? )(.+)/i || i["dedication"] =~ /(IHO )(.+)/ + JSON.generate({type: "honor", note: $+}) else - output[:dedication] = JSON.generate({type: 'honor', note: i['dedication'] }) + JSON.generate({type: "honor", note: i["dedication"]}) end output end.each do |i| - Qx.update(:donations).where('id = $id', {id: i[:id]}).set({dedication: i[:dedication]}).ex + Qx.update(:donations).where("id = $id", {id: i[:id]}).set({dedication: i[:dedication]}).ex end end def self.add_honor_to_any_json_dedications_without_type(json_dedications) - json_dedications.map{|i| {'id' => i['id'], 'dedication' => JSON::parse(i['dedication']) }} - .select{|i| !%w(honor memory).include?(i['dedication']['type'])} - .map{|i| i['dedication']['type'] = 'honor'; i } + json_dedications.map { |i| {"id" => i["id"], "dedication" => JSON.parse(i["dedication"])} } + .select { |i| !%w[honor memory].include?(i["dedication"]["type"]) } + .map { |i| + i["dedication"]["type"] = "honor" + i + } .each do |i| - Qx.update(:donations).where('id = $id', id: i['id']) - .set(dedication: JSON.generate(i['dedication'])).ex + Qx.update(:donations).where("id = $id", id: i["id"]) + .set(dedication: JSON.generate(i["dedication"])).ex end end - - - -end \ No newline at end of file +end diff --git a/app/legacy_lib/maintain_donation_validity.rb b/app/legacy_lib/maintain_donation_validity.rb index 24e5ed599..40a9290ed 100644 --- a/app/legacy_lib/maintain_donation_validity.rb +++ b/app/legacy_lib/maintain_donation_validity.rb @@ -1,21 +1,19 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module MaintainDonationValidity - # some tickets have invalid records. Find them. def self.get_invalid_donations invalid = [] - - Donation.includes( {:supporter => :nonprofit}, {:payment => :supporter }, :nonprofit, :campaign_gifts, :campaign).find_each(batch_size: 10000) do | d| - - donation = {donation:d, issues:[]} + + Donation.includes({supporter: :nonprofit}, {payment: :supporter}, :nonprofit, :campaign_gifts, :campaign).find_each(batch_size: 10000) do |d| + donation = {donation: d, issues: []} first_level(donation) - if (donation[:issues].any?) + if donation[:issues].any? invalid.push(donation) else second_level(donation) - if (donation[:issues].any?) + if donation[:issues].any? invalid.push(donation) end end @@ -29,7 +27,7 @@ def self.get_invalid_donations # some tickets have valid records, format a report of them def self.report(invalid_records) - output = invalid_records.map{|d| + invalid_records.map { |d| donation = d[:donation] { donation_id: donation.id, @@ -46,7 +44,7 @@ def self.report(invalid_records) donation_card_holder: donation.card&.holder_id, donation_campaign_id: donation.campaign_id, donation_campaign_exists: !donation.campaign.nil?, - donation_campaign_gift: donation.campaign_gifts.map{|i| i.id}.join(', '), + donation_campaign_gift: donation.campaign_gifts.map { |i| i.id }.join(", "), donation_recurring_donation_active: donation.recurring_donation&.active, donation_recurring_donation_failures: donation.recurring_donation&.n_failures, errors: d[:issues] @@ -92,7 +90,6 @@ def self.second_level(donation) def self.cleanup(invalid_donations) Qx.transaction do invalid_donations.each do |d| - if d[:issues].include?(:no_supporter) cleanup_for_no_supporter(d[:donation]) end @@ -110,20 +107,20 @@ def self.cleanup(invalid_donations) def self.cleanup_for_no_supporter(donation) np = donation.nonprofit - if (np && !Supporter.exists?(donation.supporter_id)) - if (donation.payment&.supporter && donation.payment.supporter.nonprofit == np) + if np && !Supporter.exists?(donation.supporter_id) + if donation.payment&.supporter && donation.payment.supporter.nonprofit == np donation.supporter = donation.payment.supporter donation.save! - elsif (!donation.payment&.supporter) + elsif !donation.payment&.supporter supporter = np.supporters.build supporter.deleted = true - if (donation.supporter_id) + if donation.supporter_id supporter.id = donation.supporter_id end supporter.save! - if (!donation.supporter_id) + if !donation.supporter_id donation.supporter = supporter donation.save! end @@ -132,8 +129,8 @@ def self.cleanup_for_no_supporter(donation) end def self.cleanup_for_no_nonprofit(donation) - if (!donation.nonprofit && !donation.supporter && !donation.recurring_donation && !donation.campaign && (!donation.payment || !donation.payment.nonprofit) && donation.campaign_gifts.none? && donation.activities.none?) - if (donation.payment) + if !donation.nonprofit && !donation.supporter && !donation.recurring_donation && !donation.campaign && (!donation.payment || !donation.payment.nonprofit) && donation.campaign_gifts.none? && donation.activities.none? + if donation.payment donation.payment.destroy end donation.destroy @@ -141,14 +138,14 @@ def self.cleanup_for_no_nonprofit(donation) end def self.cleanup_for_donation_and_supporter_nps_dont_match(donation) - if (!donation.supporter.nonprofit && donation.nonprofit) + if !donation.supporter.nonprofit && donation.nonprofit donation.supporter.nonprofit = donation.nonprofit donation.supporter.save! end end def self.delete_donation_fully(donation) - if (donation.campaign_gifts.any?) + if donation.campaign_gifts.any? donation.campaign_gifts.destroy_all end @@ -161,17 +158,26 @@ def self.change_all_donation_to_supporter(d, new_supporter) d.supporter = new_supporter d.save! - d.activities&.each{|i| i.supporter = new_supporter; i.save!} - d.payments&.each{|i| i.supporter = new_supporter; i.save!} + d.activities&.each { |i| + i.supporter = new_supporter + i.save! + } + d.payments&.each { |i| + i.supporter = new_supporter + i.save! + } - d.charges&.each{|i| i.supporter = new_supporter; i.save!} - if (d.card) - d.card.charges.any?{|c| !d.charges.include?(c)} - d.card.holder = new_supporter + d.charges&.each { |i| + i.supporter = new_supporter + i.save! + } + if d.card + d.card.charges.any? { |c| !d.charges.include?(c) } + d.card.holder = new_supporter d.card.save! end - if (d.recurring_donation) + if d.recurring_donation d.recurring_donation.supporter = new_supporter d.recurring_donation.save! end @@ -192,4 +198,4 @@ def self.create_new_supporter_on_correct_np(nonprofit, old_supporter) supporter.save! supporter end -end \ No newline at end of file +end diff --git a/app/legacy_lib/maintain_payment_records.rb b/app/legacy_lib/maintain_payment_records.rb index b95edf92a..5a61fab77 100644 --- a/app/legacy_lib/maintain_payment_records.rb +++ b/app/legacy_lib/maintain_payment_records.rb @@ -2,11 +2,11 @@ module MaintainPaymentRecords # For records which have no associated charge, refund, nonprofit, supporter, donation or a gross_amount # The record is basically useless def self.find_records_which_are_really_bad - Payment.includes(:charges).includes(:refund).where('payments.nonprofit_id IS NULL AND payments.supporter_id IS NULL AND payments.donation_id IS NULL AND payments.gross_amount IS NULL AND charges.id IS NULL AND refunds.id IS NULL') + Payment.includes(:charges).includes(:refund).where("payments.nonprofit_id IS NULL AND payments.supporter_id IS NULL AND payments.donation_id IS NULL AND payments.gross_amount IS NULL AND charges.id IS NULL AND refunds.id IS NULL") end def self.set_payment_supporter_and_nonprofit_though_charge_refund(i) - p = Payment.includes(:refund => :charge).find(i) + p = Payment.includes(refund: :charge).find(i) p.supporter_id = p.refund.charge.supporter_id p.nonprofit_id = p.refund.charge.nonprofit_id p.refund.disbursed = true @@ -16,9 +16,9 @@ def self.set_payment_supporter_and_nonprofit_though_charge_refund(i) def self.delete_payment_and_offsite_payment_record(id) p = Payment.includes(:offsite_payment).find(id) - if (p.offsite_payment) + if p.offsite_payment p.offsite_payment.destroy end p.destroy end -end \ No newline at end of file +end diff --git a/app/legacy_lib/maintain_payments_where_supporter_is_gone.rb b/app/legacy_lib/maintain_payments_where_supporter_is_gone.rb index 6e5369b11..e715a26d2 100644 --- a/app/legacy_lib/maintain_payments_where_supporter_is_gone.rb +++ b/app/legacy_lib/maintain_payments_where_supporter_is_gone.rb @@ -1,107 +1,95 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module MaintainPaymentsWhereSupporterIsGone - - def self.weird_records() + def self.weird_records Payment.find_by_sql('SELECT payments.* from payments LEFT JOIN supporters ON payments.supporter_id = supporters.id WHERE payments.supporter_id IS NOT NULL AND supporters.id IS NULL') end - def self.records_by_nonprofit_urgency( records ) - records_by_nonprofit_urgency = records.group_by{|i| i.nonprofit_id}.sort_by{|k,v| v.count}.reverse - records_by_nonprofit_urgency.map{|k,v| [k, v.count]}.each{|k,v| puts "#{k}: #{v} records"} - return records_by_nonprofit_urgency + def self.records_by_nonprofit_urgency(records) + records_by_nonprofit_urgency = records.group_by { |i| i.nonprofit_id }.sort_by { |k, v| v.count }.reverse + records_by_nonprofit_urgency.map { |k, v| [k, v.count] }.each { |k, v| puts "#{k}: #{v} records" } + records_by_nonprofit_urgency end - def self.sorted_by_kind( records ) - sorted_by_kind = records.group_by{|i| i.kind}.sort_by{|k,v| v.count}.reverse - sorted_by_kind.map{|k,v| [k, v.count]}.each{|k,v| puts "#{k}: #{v} records"} - return sorted_by_kind + def self.sorted_by_kind(records) + sorted_by_kind = records.group_by { |i| i.kind }.sort_by { |k, v| v.count }.reverse + sorted_by_kind.map { |k, v| [k, v.count] }.each { |k, v| puts "#{k}: #{v} records" } + sorted_by_kind end - def self.nonprofit_by_kind( urgency ) - nonprofit_by_kind = urgency.map{|k,v| [k, v.group_by{|i|i.kind}.sort_by{|i,x| x.count}.reverse.map{|i,x| [i, x.count]}]} - nonprofit_by_kind.each{|id,group| puts id; group.each{|kind, num| puts " #{kind}: #{num}"}} + def self.nonprofit_by_kind(urgency) + nonprofit_by_kind = urgency.map { |k, v| [k, v.group_by { |i| i.kind }.sort_by { |i, x| x.count }.reverse.map { |i, x| [i, x.count] }] } + nonprofit_by_kind.each { |id, group| + puts id + group.each { |kind, num| puts " #{kind}: #{num}" } + } nonprofit_by_kind end - - - - - def self.cleanup(sorted_by_kind, api_key) - Qx.transaction do + Qx.transaction do manual_payments = [] - recurring_donations_from_stripe = sorted_by_kind[1][1].select{|i| i.charge && i.charge.stripe_charge_id && !i.charge.stripe_charge_id.start_with?('legacy')} - donations_from_stripe = sorted_by_kind[2][1].select{|i| i.charge && i.charge.stripe_charge_id && !i.charge.stripe_charge_id.start_with?('legacy')} - ticket_from_stripe = sorted_by_kind[3][1].select{|i| i.charge && i.charge.stripe_charge_id && !i.charge.stripe_charge_id.start_with?('legacy')} - + recurring_donations_from_stripe = sorted_by_kind[1][1].select { |i| i.charge && i.charge.stripe_charge_id && !i.charge.stripe_charge_id.start_with?("legacy") } + donations_from_stripe = sorted_by_kind[2][1].select { |i| i.charge && i.charge.stripe_charge_id && !i.charge.stripe_charge_id.start_with?("legacy") } + ticket_from_stripe = sorted_by_kind[3][1].select { |i| i.charge && i.charge.stripe_charge_id && !i.charge.stripe_charge_id.start_with?("legacy") } + payments = recurring_donations_from_stripe.concat(donations_from_stripe).concat(ticket_from_stripe) - - payments.each do |i| - begin - unless Supporter.exists?(i.supporter_id) || i.nonprofit_id == 4500 - ch = Stripe::Charge.retrieve(i.charge.stripe_charge_id, {api_key: api_key}) - billing_name = ch.billing_details['name'] - cust = Stripe::Customer.retrieve(ch.customer, {api_key: api_key}) - email = cust.email - - #where we save the Supporter - s = Supporter.create(id: i.supporter_id, name: billing_name, email: email, created_at: i.created_at, nonprofit_id: i.nonprofit_id ) - s.save! - puts "#{i.supporter_id} is saved" - else - puts "#{i.supporter_id} was already saved" - end - rescue => e - puts e - puts "we failed on #{i.id}" - manual_payments.push(i) - + payments.each do |i| + if Supporter.exists?(i.supporter_id) || i.nonprofit_id == 4500 + puts "#{i.supporter_id} was already saved" + else + ch = Stripe::Charge.retrieve(i.charge.stripe_charge_id, {api_key: api_key}) + billing_name = ch.billing_details["name"] + cust = Stripe::Customer.retrieve(ch.customer, {api_key: api_key}) + email = cust.email + + # where we save the Supporter + s = Supporter.create(id: i.supporter_id, name: billing_name, email: email, created_at: i.created_at, nonprofit_id: i.nonprofit_id) + s.save! + puts "#{i.supporter_id} is saved" end + rescue => e + puts e + + puts "we failed on #{i.id}" + manual_payments.push(i) end - - manual_refunds = [] #we have to manually track down these refunds on the connected accounts - refunds = sorted_by_kind[4][1].select{|i| i.refund && i.refund.stripe_refund_id} - + + manual_refunds = [] # we have to manually track down these refunds on the connected accounts + refunds = sorted_by_kind[4][1].select { |i| i.refund && i.refund.stripe_refund_id } + refunds.each do |i| - begin - unless Supporter.exists?(i.supporter_id) - refund = Stripe::Refund.retrieve(i.refund.stripe_refund_id, {api_key: api_key}) - billing_name = refund.billing_details['name'] - cust = Stripe::Customer.retrieve(refund.customer, {api_key: api_key}) - email = cust.email - - #where we save the Supporter - Supporter.create(id: i.supporter_id, name: billing_name, email: email, created_at: i.created_at ) - end - rescue - manual_refunds.push(i) - + unless Supporter.exists?(i.supporter_id) + refund = Stripe::Refund.retrieve(i.refund.stripe_refund_id, {api_key: api_key}) + billing_name = refund.billing_details["name"] + cust = Stripe::Customer.retrieve(refund.customer, {api_key: api_key}) + email = cust.email + + # where we save the Supporter + Supporter.create(id: i.supporter_id, name: billing_name, email: email, created_at: i.created_at) end + rescue + manual_refunds.push(i) end - - disputes = sorted_by_kind[5][1].select{|i| i.dispute && i.dispute.stripe_dispute_id} + + disputes = sorted_by_kind[5][1].select { |i| i.dispute && i.dispute.stripe_dispute_id } manual_disputes = [] # ditto - + disputes.each do |i| - begin - unless Supporter.exists?(i.supporter_id) - dispute = Stripe::Dispute.retrieve(i.refund.stripe_refund_id, {api_key: api_key}) - billing_name = dispute.billing_details['name'] - cust = Stripe::Customer.retrieve(dispute.customer, {api_key: api_key}) - email = cust.email - - #where we save the Supporter - Supporter.create(id: i.supporter_id, name: billing_name, email: email, created_at: i.created_at ) - end - rescue - manual_disputes.push(i) - + unless Supporter.exists?(i.supporter_id) + dispute = Stripe::Dispute.retrieve(i.refund.stripe_refund_id, {api_key: api_key}) + billing_name = dispute.billing_details["name"] + cust = Stripe::Customer.retrieve(dispute.customer, {api_key: api_key}) + email = cust.email + + # where we save the Supporter + Supporter.create(id: i.supporter_id, name: billing_name, email: email, created_at: i.created_at) end + rescue + manual_disputes.push(i) end {manual_payments: manual_payments, manual_refunds: manual_refunds, manual_disputes: manual_disputes} end diff --git a/app/legacy_lib/maintain_stripe_records.rb b/app/legacy_lib/maintain_stripe_records.rb index 55babf1b0..6a2ccffa7 100644 --- a/app/legacy_lib/maintain_stripe_records.rb +++ b/app/legacy_lib/maintain_stripe_records.rb @@ -1,12 +1,10 @@ module MaintainStripeRecords - def self.safely_fill_stripe_charge_object(stripe_charge_id) LockManager.with_transaction_lock(stripe_charge_id) do unless StripeCharge.where("stripe_charge_id = ?", stripe_charge_id).any? object = Stripe::Charge.retrieve(stripe_charge_id) - StripeCharge.create!(object:object) + StripeCharge.create!(object: object) end end end - -end \ No newline at end of file +end diff --git a/app/legacy_lib/maintain_ticket_records.rb b/app/legacy_lib/maintain_ticket_records.rb index d4035197a..f9caa1248 100644 --- a/app/legacy_lib/maintain_ticket_records.rb +++ b/app/legacy_lib/maintain_ticket_records.rb @@ -1,18 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module MaintainTicketRecords - # a function for taking every ticket record with a card and creating a token # if the event was in the last two weeks def self.tokenize_cards_already_on_tickets Qx.transaction do - event_ids = Event.where('end_datetime >= ?', Time.current-2.weeks).pluck(:id) + event_ids = Event.where("end_datetime >= ?", 2.weeks.ago).pluck(:id) - t = Ticket.includes(:card).includes(:event).where('card_id IS NOT NULL and event_id IN (?)', event_ids) - t.each{|i| - token = InsertSourceToken.create_record(i.card, {event: i.event}) + t = Ticket.includes(:card).includes(:event).where("card_id IS NOT NULL and event_id IN (?)", event_ids) + t.each { |i| + token = InsertSourceToken.create_record(i.card, {event: i.event}) i.source_token = token i.save! } end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/maintain_ticket_validity.rb b/app/legacy_lib/maintain_ticket_validity.rb index b9a6b190c..3ef3ad57f 100644 --- a/app/legacy_lib/maintain_ticket_validity.rb +++ b/app/legacy_lib/maintain_ticket_validity.rb @@ -1,27 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module MaintainTicketValidity - # some tickets have invalid records. Find them. def self.get_invalid_tickets - tickets = Ticket.includes({:charge => [{:supporter => [:nonprofit]}]}, {:supporter => :nonprofit}, {:payment => [{:supporter => :nonprofit}, :nonprofit]}, {:event => :nonprofit}) - tickets = tickets.map{|t| {ticket:t, issues:[]}} + tickets = Ticket.includes({charge: [{supporter: [:nonprofit]}]}, {supporter: :nonprofit}, {payment: [{supporter: :nonprofit}, :nonprofit]}, {event: :nonprofit}) + tickets = tickets.map { |t| {ticket: t, issues: []} } - invalid = [] + invalid = [] - first_level(tickets) + first_level(tickets) - a, tickets = tickets.partition{|i| i[:issues].any?} - invalid = invalid.concat a + a, tickets = tickets.partition { |i| i[:issues].any? } + invalid = invalid.concat a - second_level(tickets) - a, tickets = tickets.partition{|i| i[:issues].any?} - invalid = invalid.concat(a) - invalid + second_level(tickets) + a, _ = tickets.partition { |i| i[:issues].any? } + invalid.concat(a) end # some tickets have valid records, format a report of them def self.report(invalid_records) - output = invalid_records.map{|t| + invalid_records.map { |t| ticket = t[:ticket] { ticket_id: ticket.id, @@ -112,15 +110,15 @@ def self.cleanup(invalid_tickets, profile_id) def self.cleanup_for_no_supporter(ticket) np = ticket.event&.nonprofit - if (np && !Supporter.exists?(ticket.supporter_id)) + if np && !Supporter.exists?(ticket.supporter_id) supporter = np.supporters.build supporter.deleted = true - if (ticket.supporter_id) + if ticket.supporter_id supporter.id = ticket.supporter_id end supporter.save! - if (!ticket.supporter_id) + if !ticket.supporter_id ticket.supporter = supporter ticket.save! end @@ -129,19 +127,19 @@ def self.cleanup_for_no_supporter(ticket) def self.cleanup_for_no_event(ticket, profile_id) np = ticket.supporter&.nonprofit - if(np && !(Event.exists?(ticket.event_id))) + if np && !Event.exists?(ticket.event_id) event = np.events.build event.deleted = true event.name = "Unnamed event #{ticket.event_id || rand(3000)}" event.start_datetime = ticket.created_at event.end_datetime = ticket.created_at + 1.hour - event.address = 'unknown' + event.address = "unknown" event.city = "city" event.state_code = "wi" event.zip_code = "55555" event.profile_id = profile_id event.slug = "unnamed_event__#{rand(4400)}" - if (ticket.event_id) + if ticket.event_id event.id = ticket.event_id end event.save! @@ -166,16 +164,15 @@ def self.cleanup_for_event_and_supporter_nps_dont_match(ticket) ticket.supporter = supporter ticket.save! - end def self.find_ticket_groups - payments = Ticket.select('payment_id').where('payment_id IS NOT NULL').group('payment_id').map{|i| i.payment_id} + payments = Ticket.select("payment_id").where.not(payment_id: nil).group("payment_id").map { |i| i.payment_id } - payments.select do |p| - tickets = Ticket.where('payment_id = ? ', p) + payments.select do |p| + tickets = Ticket.where("payment_id = ? ", p) supporter = tickets.first.supporter_id - !tickets.all? {|t| t.supporter_id == supporter} + !tickets.all? { |t| t.supporter_id == supporter } end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/merge_supporters.rb b/app/legacy_lib/merge_supporters.rb index 5394f8892..922688aca 100644 --- a/app/legacy_lib/merge_supporters.rb +++ b/app/legacy_lib/merge_supporters.rb @@ -1,12 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - module MergeSupporters - +module MergeSupporters # For supporters that have been merged, we want to update all their child tables to the new supporter_id def self.update_associations(old_supporters, new_supporter, np_id, profile_id) new_supporter_id = new_supporter.id - old_supporter_ids = old_supporters.map{|i| i.id} + old_supporter_ids = old_supporters.map { |i| i.id } # The new supporter needs to have the following tables from the merged supporters: - associations = [:activities, :donations, :recurring_donations, :offsite_payments, :payments, :tickets, :supporter_notes, :supporter_emails, :full_contact_infos] + associations = [:activities, :donations, :recurring_donations, :offsite_payments, :payments, :tickets, :supporter_notes, :supporter_emails, :full_contact_infos] associations.each do |table_name| Qx.update(table_name) @@ -22,72 +21,75 @@ def self.update_associations(old_supporters, new_supporter, np_id, profile_id) end old_supporters = old_supporters.includes(:tag_joins).includes(:custom_field_joins) - old_tags = old_supporters.map{|i| i.tag_joins.map{|j| j.tag_master}}.flatten.uniq + old_tags = old_supporters.map { |i| i.tag_joins.map { |j| j.tag_master } }.flatten.uniq - #delete old tags + # delete old tags InsertTagJoins.in_bulk(np_id, profile_id, old_supporter_ids, - old_tags.map{|i| {tag_master_id: i.id, selected: false}}) - + old_tags.map { |i| {tag_master_id: i.id, selected: false} }) - InsertTagJoins.in_bulk(np_id, profile_id, [new_supporter_id], old_tags.map{|i| {tag_master_id: i.id, selected: true}}) + InsertTagJoins.in_bulk(np_id, profile_id, [new_supporter_id], old_tags.map { |i| {tag_master_id: i.id, selected: true} }) - all_custom_field_joins = old_supporters.map{| i| i.custom_field_joins}.flatten - group_joins_by_custom_field_master = all_custom_field_joins.group_by{|i| i.custom_field_master.id} - one_custom_field_join_per_user = group_joins_by_custom_field_master.map{|k,v| - v.sort_by{|i| + all_custom_field_joins = old_supporters.map { |i| i.custom_field_joins }.flatten + group_joins_by_custom_field_master = all_custom_field_joins.group_by { |i| i.custom_field_master.id } + one_custom_field_join_per_user = group_joins_by_custom_field_master.map { |k, v| + v.sort_by { |i| i.created_at - }.reverse.first} + }.last + } - #delete old supporter custom_field - InsertCustomFieldJoins.in_bulk(np_id, old_supporter_ids, one_custom_field_join_per_user.map{|i| { + # delete old supporter custom_field + InsertCustomFieldJoins.in_bulk(np_id, old_supporter_ids, one_custom_field_join_per_user.map { |i| + { custom_field_master_id: i.custom_field_master_id, value: "" - }}) + } + }) - #insert new supporter custom field - InsertCustomFieldJoins.in_bulk(np_id, [new_supporter_id], one_custom_field_join_per_user.map{|i| { + # insert new supporter custom field + InsertCustomFieldJoins.in_bulk(np_id, [new_supporter_id], one_custom_field_join_per_user.map { |i| + { custom_field_master_id: i.custom_field_master_id, value: i.value - }}) + } + }) # Update all deleted/merged supporters to record when and where they got merged Psql.execute(Qexpr.new.update(:supporters, {merged_at: Time.current, merged_into: new_supporter_id}).where("id IN ($ids)", ids: old_supporter_ids)) # Removing any duplicate custom fields UpdateCustomFieldJoins.delete_dupes([new_supporter_id]) end - def self.selected(merged_data, supporter_ids,np_id, profile_id, skip_conflicting_custom_fields=false) - old_supporters = Nonprofit.find(np_id).supporters.where('supporters.id IN (?)', supporter_ids) + def self.selected(merged_data, supporter_ids, np_id, profile_id, skip_conflicting_custom_fields = false) + old_supporters = Nonprofit.find(np_id).supporters.where("supporters.id IN (?)", supporter_ids) if skip_conflicting_custom_fields && conflicting_custom_fields?(old_supporters) - return { json: supporter_ids, status: :failure } + return {json: supporter_ids, status: :failure} end - merged_data['anonymous'] = old_supporters.any?{|i| i.anonymous} + merged_data["anonymous"] = old_supporters.any? { |i| i.anonymous } new_supporter = Nonprofit.find(np_id).supporters.create!(merged_data) # Update merged supporters as deleted Psql.execute(Qexpr.new.update(:supporters, {deleted: true}).where("supporters.id IN ($ids)", ids: supporter_ids)) # Update all associated tables - self.update_associations(old_supporters, new_supporter, np_id, profile_id) - return {json: new_supporter, status: :ok} + update_associations(old_supporters, new_supporter, np_id, profile_id) + {json: new_supporter, status: :ok} end def self.conflicting_custom_fields?(supporters) cfjs = [] supporters.each do |supporter| supporter.custom_field_joins.each do |cfj| - cfjs << { 'custom_field_master_id' => cfj.custom_field_master_id, 'value' => cfj.value } + cfjs << {"custom_field_master_id" => cfj.custom_field_master_id, "value" => cfj.value} end end - cfjs.group_by{|i| i['custom_field_master_id']}.any?{ |id, group| group.uniq.size > 1 } + cfjs.group_by { |i| i["custom_field_master_id"] }.any? { |id, group| group.uniq.size > 1 } end - # Merge supporters for a nonprofit based on an array of groups of ids, generated from QuerySupporters.dupes_on_email or dupes_on_names # @return [Array[Array]] an array of arrays of supporter_ids that have conflicting custom fields between them. - def self.merge_by_id_groups(np_id, arr_of_ids, profile_id, skip_conflicting_custom_fields=false) + def self.merge_by_id_groups(np_id, arr_of_ids, profile_id, skip_conflicting_custom_fields = false) supporter_ids_with_conflicting_custom_fields = [] - arr_of_ids.select{|arr| arr.count > 1}.each do |ids| + arr_of_ids.select { |arr| arr.count > 1 }.each do |ids| Qx.transaction do # Get all column data from every supporter all_data = Psql.execute( @@ -97,10 +99,9 @@ def self.merge_by_id_groups(np_id, arr_of_ids, profile_id, skip_conflicting_cust .order_by("created_at ASC") ) # Use the most recent non null/blank column data for the new supporter - data = all_data.reduce({}) do |acc, supp| - supp.except('created_at').each{|key, val| acc[key] = val unless val.blank?} - acc - end.merge({'nonprofit_id' => np_id}) + data = all_data.each_with_object({}) do |supp, acc| + supp.except("created_at").each { |key, val| acc[key] = val unless val.blank? } + end.merge({"nonprofit_id" => np_id}) result = MergeSupporters.selected(data, ids, np_id, profile_id, skip_conflicting_custom_fields) supporter_ids_with_conflicting_custom_fields << ids if result[:status] == :failure diff --git a/app/legacy_lib/migrate/migrate_cover_fees.rb b/app/legacy_lib/migrate/migrate_cover_fees.rb index 1b5d8d86c..5438d46a5 100644 --- a/app/legacy_lib/migrate/migrate_cover_fees.rb +++ b/app/legacy_lib/migrate/migrate_cover_fees.rb @@ -2,10 +2,8 @@ module Migrate class MigrateCoverFees def self.for_nonprofits MiscellaneousNpInfo.all.each do |mni| - if (mni.hide_cover_fees) - mni.fee_coverage_option_config = 'none' - else - mni.fee_coverage_option_config = nil + mni.fee_coverage_option_config = if mni.hide_cover_fees + "none" end mni.save! end @@ -13,19 +11,15 @@ def self.for_nonprofits def self.for_campaigns MiscCampaignInfo.all.each do |mci| - if (mci.campaign.nonprofit.hide_cover_fees? ) - mci.fee_coverage_option_config = nil - else - if (mci.hide_cover_fees_option?) - mci.fee_coverage_option_config = 'none' - elsif (mci.manual_cover_fees?) - mci.fee_coverage_option_config = 'manual' - else - mci.fee_coverage_option_config = nil - end + mci.fee_coverage_option_config = if mci.campaign.nonprofit.hide_cover_fees? + nil + elsif mci.hide_cover_fees_option? + "none" + elsif mci.manual_cover_fees? + "manual" end mci.save! end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/multiple_condition_search.rb b/app/legacy_lib/multiple_condition_search.rb index 5e59852e5..300a6a07a 100644 --- a/app/legacy_lib/multiple_condition_search.rb +++ b/app/legacy_lib/multiple_condition_search.rb @@ -6,7 +6,7 @@ # # Assumption: the searches start from the least complex and go up. Probably won't work another way. -# A multiple condition search like that can end in a few different ways: +# A multiple condition search like that can end in a few different ways: # * we get to a condition and there are no records # * we get to the last condition and there are mulitiple records left # * we get to a condition where there is a single record (success!) @@ -15,9 +15,9 @@ # search = MultipleConditionSearch.new([ # ['name = ?', "Penelope Schultz"], # you can use any of the styles used by `#where` # {name: "Penelope Schultz", email: 'penelope@schultz.household'} -# ]) +# ]) # result = search.find(Nonprofit.find(12356).supporters) # result is nil if there was an error otherwise, we get the result -# +# # puts 'There were no records found' if search.error == :none # puts 'There were multiple records on the last condition' if search.error == :multiple_values # @@ -28,7 +28,7 @@ # if result # puts result.id # end -# +# class MultipleConditionSearch @subconditions = [] @@ -38,9 +38,9 @@ class MultipleConditionSearch # @return [Symbol,nil] nil if a single result was found at one point. :none if a condition returned no values, :multiple_values if # we got to the last condition and there were multiple records attr_reader :error - - # @!attribute result the result of the last condition attempted in the find. - # @return [nil,ActiveRecord::Base,ActiveRecord::Relation] nil if the last condition attempted returned no records, + + # @!attribute result the result of the last condition attempted in the find. + # @return [nil,ActiveRecord::Base,ActiveRecord::Relation] nil if the last condition attempted returned no records, # ActiveRecord::Base if the last query attempted had a single record and ActiveRecord::Relation if the last condition # attempted had multiple records attr_reader :result @@ -48,8 +48,8 @@ class MultipleConditionSearch # Important note: you MUST wrap all of your conditions into an array # @param [Array[string,Array,Hash]] args the subconditions attempted. Each of these correspond to the values you would pass into # the method of where. For example, you could - - def initialize(args=[]) + + def initialize(args = []) @subconditions = args @error = nil @result = nil @@ -74,4 +74,4 @@ def find(relation) end raise "should never happen" end -end \ No newline at end of file +end diff --git a/app/legacy_lib/name_copy_naming_algorithm.rb b/app/legacy_lib/name_copy_naming_algorithm.rb index 1094b99bd..95d932e1d 100644 --- a/app/legacy_lib/name_copy_naming_algorithm.rb +++ b/app/legacy_lib/name_copy_naming_algorithm.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class NameCopyNamingAlgorithm < CopyNamingAlgorithm - attr_accessor :klass, :nonprofit_id # @param [Class] klass def initialize(klass, nonprofit_id) - @klass = klass - @nonprofit_id = nonprofit_id + @klass = klass + @nonprofit_id = nonprofit_id end def copy_addition - " (#{Time.now.strftime('%F')} copy)" + " (#{Time.now.strftime("%F")} copy)" end def separator_before_copy_number @@ -29,13 +28,12 @@ def get_name_for_entity(name_entity) end def get_already_used_name_entities(base_name) - end_name = "#{copy_addition.gsub("(","\\(").gsub(")", "\\)")} \\d{2}" + end_name = "#{copy_addition.gsub("(", "\\(").gsub(")", "\\)")} \\d{2}" end_name_length = copy_addition.length + 3 amount_to_strip = end_name_length + base_name.length - max_length - if (amount_to_strip < 0) + if amount_to_strip < 0 amount_to_strip = 0 end - @klass.method(:where).call('name SIMILAR TO ? AND nonprofit_id = ?', "#{base_name[0..base_name.length-amount_to_strip-1]}_*" + end_name, nonprofit_id).select('name') + @klass.method(:where).call("name SIMILAR TO ? AND nonprofit_id = ?", "#{base_name[0..base_name.length - amount_to_strip - 1]}_*" + end_name, nonprofit_id).select("name") end - -end \ No newline at end of file +end diff --git a/app/legacy_lib/nonprofit_metrics.rb b/app/legacy_lib/nonprofit_metrics.rb index 0f19322f9..28c46c620 100644 --- a/app/legacy_lib/nonprofit_metrics.rb +++ b/app/legacy_lib/nonprofit_metrics.rb @@ -1,23 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module NonprofitMetrics - def self.payments(np_id) Qx.select( "(SUM(payments.gross_amount) / 100.0)::money::text AS total", "(AVG(payments.gross_amount) / 100.0)::money::text AS average", "(SUM(week.gross_amount) / 100.0)::money::text AS week", "(SUM(month.gross_amount) / 100.0)::money::text AS month", - "(SUM(year.gross_amount) / 100.0)::money::text AS year", - ) - .from(:payments) - .left_join( - ['payments week', "week.id=payments.id AND week.date > date_trunc('week', NOW())"], - ['payments month', "month.id=payments.id AND month.date > date_trunc('month', NOW())"], - ['payments year', "year.id=payments.id AND year.date > date_trunc('year', NOW())"] + "(SUM(year.gross_amount) / 100.0)::money::text AS year" ) - .where("payments.nonprofit_id=$id", id: np_id) - .execute.last + .from(:payments) + .left_join( + ["payments week", "week.id=payments.id AND week.date > date_trunc('week', NOW())"], + ["payments month", "month.id=payments.id AND month.date > date_trunc('month', NOW())"], + ["payments year", "year.id=payments.id AND year.date > date_trunc('year', NOW())"] + ) + .where("payments.nonprofit_id=$id", id: np_id) + .execute.last end def self.recurring(np_id) @@ -25,14 +24,14 @@ def self.recurring(np_id) Qx.select( "(SUM(recurring_donations.amount) / 100.0)::money::text AS total", "(AVG(recurring_donations.amount) / 100.0)::money::text AS average", - "(SUM(month.amount) / 100.0)::money::text AS month", + "(SUM(month.amount) / 100.0)::money::text AS month" ) - .from(:recurring_donations) - .left_join("recurring_donations month", "month.id=recurring_donations.id AND month.created_at > date_trunc('month', NOW())") - .where("recurring_donations.active=TRUE") - .and_where("recurring_donations.n_failures < 3") - .and_where("recurring_donations.nonprofit_id=$id", id: np_id) - .execute.last + .from(:recurring_donations) + .left_join("recurring_donations month", "month.id=recurring_donations.id AND month.created_at > date_trunc('month', NOW())") + .where("recurring_donations.active=TRUE") + .and_where("recurring_donations.n_failures < 3") + .and_where("recurring_donations.nonprofit_id=$id", id: np_id) + .execute.last end def self.supporters(np_id) @@ -41,12 +40,12 @@ def self.supporters(np_id) "COUNT(week) AS week", "COUNT(month) AS month" ) - .from(:supporters) - .left_join("supporters week", "week.id=supporters.id AND week.created_at > date_trunc('week', NOW()) AND week.imported_at IS NULL") - .add_left_join("supporters month", "month.id=supporters.id AND month.created_at > date_trunc('month', NOW()) AND month.imported_at IS NULL") - .where("coalesce(supporters.deleted, FALSE) = FALSE") - .and_where("supporters.nonprofit_id=$id", id: np_id) - .execute.last + .from(:supporters) + .left_join("supporters week", "week.id=supporters.id AND week.created_at > date_trunc('week', NOW()) AND week.imported_at IS NULL") + .add_left_join("supporters month", "month.id=supporters.id AND month.created_at > date_trunc('month', NOW()) AND month.imported_at IS NULL") + .where("coalesce(supporters.deleted, FALSE) = FALSE") + .and_where("supporters.nonprofit_id=$id", id: np_id) + .execute.last end def self.recent_donations(np_id) @@ -58,31 +57,30 @@ def self.recent_donations(np_id) "supporters.email AS supporter_email", "'/nonprofits/#{np_id}/payments?pid=' || payments.id AS payment_url" ) - .from(:payments) - .join("supporters", "payments.supporter_id=supporters.id") - .where("payments.nonprofit_id=$id", id: np_id) - .and_where("payments.kind IN ('Donation', 'RecurringDonation', 'Ticket')") - .limit(10) - .order_by("payments.date DESC") - .execute + .from(:payments) + .join("supporters", "payments.supporter_id=supporters.id") + .where("payments.nonprofit_id=$id", id: np_id) + .and_where("payments.kind IN ('Donation', 'RecurringDonation', 'Ticket')") + .limit(10) + .order_by("payments.date DESC") + .execute end def self.recent_supporters(np_id) Qx.select("name", "email", "id", "created_at") - .from(:supporters) - .where("supporters.nonprofit_id=$id", id: np_id) - .and_where("coalesce(supporters.deleted, FALSE) = FALSE") - .and_where("supporters.import_id IS NULL") - .limit(10) - .order_by("supporters.created_at DESC") - .execute + .from(:supporters) + .where("supporters.nonprofit_id=$id", id: np_id) + .and_where("coalesce(supporters.deleted, FALSE) = FALSE") + .and_where("supporters.import_id IS NULL") + .limit(10) + .order_by("supporters.created_at DESC") + .execute end def self.all_metrics(np_id) keys = [:payments, :recurring, :supporters, :recent_donations, :recent_supporters, :published_campaigns] - keys.reduce({}) do |accum, elem| + keys.each_with_object({}) do |elem, accum| accum[elem] = NonprofitMetrics.send(elem, np_id) - accum end end @@ -96,16 +94,16 @@ def self.published_campaigns(np_id) "(SUM(one_time.amount)/ 100)::money::text AS total_one_time", "(SUM(recurring_donations.amount)/ 100)::money::text AS total_recurring" ) - .from(:campaigns) - .left_join("donations", "donations.campaign_id=campaigns.id") - .add_left_join("donations AS one_time", "donations.id=one_time.id AND one_time.recurring_donation_id IS NULL") - .add_left_join("recurring_donations", "recurring_donations.donation_id=donations.id AND recurring_donations.active=TRUE") - .add_left_join("supporters", "supporters.id=donations.supporter_id") - .group_by("campaigns.id") - .where("campaigns.nonprofit_id=$id", id: np_id) - .and_where("campaigns.published = TRUE") - .order_by("campaigns.end_datetime DESC") - .execute + .from(:campaigns) + .left_join("donations", "donations.campaign_id=campaigns.id") + .add_left_join("donations AS one_time", "donations.id=one_time.id AND one_time.recurring_donation_id IS NULL") + .add_left_join("recurring_donations", "recurring_donations.donation_id=donations.id AND recurring_donations.active=TRUE") + .add_left_join("supporters", "supporters.id=donations.supporter_id") + .group_by("campaigns.id") + .where("campaigns.nonprofit_id=$id", id: np_id) + .and_where("campaigns.published = TRUE") + .order_by("campaigns.end_datetime DESC") + .execute end # Given a starting date, ending date, and time interval, @@ -114,18 +112,18 @@ def self.published_campaigns(np_id) # each hash is nested in an outer hash, set to a key that is also the date, lol # this is used in the payment_history query to fill in missing dates in the data. def self.payment_history_timespans(params) - raise ArgumentError.new("Invalid timespan") unless ['year', 'month', 'week', 'day'].include? params[:timeSpan] + raise ArgumentError.new("Invalid timespan") unless ["year", "month", "week", "day"].include? params[:timeSpan] date_hash = {} - beginning_of = 'beginning_of_' + params[:timeSpan] + beginning_of = "beginning_of_" + params[:timeSpan] current_date = Chronic.parse(params[:startDate]).send(beginning_of) end_date = Chronic.parse(params[:endDate]).send(beginning_of) while current_date <= end_date date = current_date.strftime("%F") - date_hash[date] = {'time_span' => date} + date_hash[date] = {"time_span" => date} current_date += 1.send(params[:timeSpan]) end - return date_hash + date_hash end def self.payment_history(params) @@ -136,22 +134,23 @@ def self.payment_history(params) "coalesce(SUM(recurring.gross_amount ), 0) AS recurring_cents", "coalesce(SUM(tickets.gross_amount ), 0) AS tickets_cents" ) - .from(:payments) - .left_join( - ["payments AS onetime", "onetime.id=payments.id AND onetime.kind='Donation'"], - ["payments AS recurring", "recurring.id=payments.id AND recurring.kind='RecurringDonation'"], - ["payments AS tickets", "tickets.id=payments.id AND tickets.kind='Ticket'"] - ) - .where("payments.nonprofit_id" => params[:id]) - .and_where("payments.date >= $d", d: params[:startDate]) - .and_where("payments.date <= $d", d: params[:endDate]) - .group_by("date_trunc('#{params[:timeSpan]}', payments.date)") - .order_by("MAX(payments.date)") - .execute + .from(:payments) + .left_join( + ["payments AS onetime", "onetime.id=payments.id AND onetime.kind='Donation'"], + ["payments AS recurring", "recurring.id=payments.id AND recurring.kind='RecurringDonation'"], + ["payments AS tickets", "tickets.id=payments.id AND tickets.kind='Ticket'"] + ) + .where("payments.nonprofit_id" => params[:id]) + .and_where("payments.date >= $d", d: params[:startDate]) + .and_where("payments.date <= $d", d: params[:endDate]) + .group_by("date_trunc('#{params[:timeSpan]}', payments.date)") + .order_by("MAX(payments.date)") + .execute date_hash = payment_history_timespans(params) - return results.reduce(date_hash){|acc, r| acc[r['time_span']] = r; acc}.values + results.each_with_object(date_hash) { |r, acc| + acc[r["time_span"]] = r + }.values end - end diff --git a/app/legacy_lib/nonprofit_query_generator.rb b/app/legacy_lib/nonprofit_query_generator.rb index ae86cd89b..20ac006c9 100644 --- a/app/legacy_lib/nonprofit_query_generator.rb +++ b/app/legacy_lib/nonprofit_query_generator.rb @@ -8,13 +8,13 @@ def nonprofits end def supporters - Qx.select('supporters.*') + Qx.select("supporters.*") .from(:supporters) - .where("supporters.nonprofit_id = $id and deleted != 'true'", id: @id ) + .where("supporters.nonprofit_id = $id and deleted != 'true'", id: @id) end def payments - Qx.select('*').from(:payments).where("nonprofit_id = $id", id: @id) + Qx.select("*").from(:payments).where("nonprofit_id = $id", id: @id) end def supporter_notes @@ -30,4 +30,4 @@ def tag_joins_through_supporters .from(:tag_joins) .join(:supporters, "supporters.id = tag_joins.supporter_id") end -end \ No newline at end of file +end diff --git a/app/legacy_lib/not_enough_quantity_error.rb b/app/legacy_lib/not_enough_quantity_error.rb index c2048526d..10948c168 100644 --- a/app/legacy_lib/not_enough_quantity_error.rb +++ b/app/legacy_lib/not_enough_quantity_error.rb @@ -7,4 +7,4 @@ def initialize(klass, id, requested, msg) @requested = requested super(msg) end -end \ No newline at end of file +end diff --git a/app/legacy_lib/notify_user.rb b/app/legacy_lib/notify_user.rb index 1a1073f19..1eec28265 100644 --- a/app/legacy_lib/notify_user.rb +++ b/app/legacy_lib/notify_user.rb @@ -1,13 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module NotifyUser - def self.send_confirmation_email(user_id) - ParamValidation.new({user_id: user_id}, user_id: {required:true, is_integer: true}) - user = User.where('id = ?', user_id).first + ParamValidation.new({user_id: user_id}, user_id: {required: true, is_integer: true}) + user = User.where("id = ?", user_id).first if !user raise ParamValidation::ValidationError.new("#{user_id} is not a valid user id", {key: :user_id, val: user_id}) end user.send_confirmation_instructions end -end \ No newline at end of file +end diff --git a/app/legacy_lib/numeric.rb b/app/legacy_lib/numeric.rb index af0b53b83..a24074ff9 100644 --- a/app/legacy_lib/numeric.rb +++ b/app/legacy_lib/numeric.rb @@ -4,15 +4,15 @@ class Numeric # @param [Integer] delta the integer offsets from zero to round down to # @return [Integer] def floor_for_delta(delta) - raise ArgumentError.new('delta must be a positive integer') unless delta.is_a?(Integer) && delta > 0 - (self % delta).zero? ? self : ((self.to_i / delta)) * delta; + raise ArgumentError.new("delta must be a positive integer") unless delta.is_a?(Integer) && delta > 0 + (self % delta).zero? ? self : ((to_i / delta)) * delta end # Works like Numeric#ceil but uses an offset other than 1. Ex: 6.floor_for_delta(5) -> 10 # @param [Integer] delta the integer offsets from zero to round up to # @return [Integer] def ceil_for_delta(delta) - raise ArgumentError.new('delta must be a positive integer') unless delta.is_a?(Integer) && delta > 0 - (self % delta).zero? ? self : ((self.floor.to_i / delta)+1) * delta; + raise ArgumentError.new("delta must be a positive integer") unless delta.is_a?(Integer) && delta > 0 + (self % delta).zero? ? self : ((floor.to_i / delta) + 1) * delta end -end \ No newline at end of file +end diff --git a/app/legacy_lib/onboard_accounts.rb b/app/legacy_lib/onboard_accounts.rb index 0f7bc5241..3456224c1 100644 --- a/app/legacy_lib/onboard_accounts.rb +++ b/app/legacy_lib/onboard_accounts.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'param_validation' -require 'qx' +require "param_validation" +require "qx" module OnboardAccounts - def self.create_org(params) - nonprofit_data = set_nonprofit_defaults(params['nonprofit']) + nonprofit_data = set_nonprofit_defaults(params["nonprofit"]) ParamValidation.new(nonprofit_data, { name: {required: true}, # email: {required: true}, @@ -13,39 +12,39 @@ def self.create_org(params) city: {required: true}, state_code: {required: true} }) - user_data = set_user_defaults(params['user']) + user_data = set_user_defaults(params["user"]) ParamValidation.new(user_data, { name: {required: true}, email: {required: true}, password: {required: true}, phone: {required: true} }) - extra_info = params['extraInfo'] + extra_info = params["extraInfo"] nonprofit = Qx.insert_into(:nonprofits) .values(nonprofit_data).timestamps - .returning('*') + .returning("*") .execute.last billing_plan_id = Settings.default_bp.id billing_subscription = Qx.insert_into(:billing_subscriptions) .values({ - nonprofit_id: nonprofit['id'], + nonprofit_id: nonprofit["id"], billing_plan_id: billing_plan_id, - status: 'active' + status: "active" }) .timestamps.execute.last # Create the user using the User and Role models (since we have to use Devise) user = User.create!(user_data) role = Qx.insert_into(:roles) - .values(user_id: user.id, name: 'nonprofit_admin', host_id: nonprofit['id'], host_type: 'Nonprofit') + .values(user_id: user.id, name: "nonprofit_admin", host_id: nonprofit["id"], host_type: "Nonprofit") .timestamps .execute.last - self.delay.send_onboard_email(nonprofit, nonprofit_data, user_data, extra_info) + delay.send_onboard_email(nonprofit, nonprofit_data, user_data, extra_info) - return { + { nonprofit: nonprofit, user: user, role: role, @@ -54,59 +53,59 @@ def self.create_org(params) end ### ethis is a one time method in order to add a user without testing for the method. Do not use this long term - def self.create_org_with_user(params, user=nil) - nonprofit_data = set_nonprofit_defaults(params['nonprofit']) + def self.create_org_with_user(params, user = nil) + nonprofit_data = set_nonprofit_defaults(params["nonprofit"]) ParamValidation.new(nonprofit_data, { - name: {required: true}, - # email: {required: true}, - # phone: {required: true}, - city: {required: true}, - state_code: {required: true} + name: {required: true}, + # email: {required: true}, + # phone: {required: true}, + city: {required: true}, + state_code: {required: true} }) - if (!user) - user_data = set_user_defaults(params['user']) + if !user + user_data = set_user_defaults(params["user"]) ParamValidation.new(user_data, { - name: {required: true}, - email: {required: true}, - password: {required: true}, - phone: {required: true} + name: {required: true}, + email: {required: true}, + password: {required: true}, + phone: {required: true} }) end - extra_info = params['extraInfo'] + extra_info = params["extraInfo"] nonprofit = Qx.insert_into(:nonprofits) - .values(nonprofit_data).timestamps - .returning('*') - .execute.last + .values(nonprofit_data).timestamps + .returning("*") + .execute.last # Create a billing subscription for the 6% fee tier billing_plan_id = Settings.default_bp.id billing_subscription = Qx.insert_into(:billing_subscriptions) - .values({ - nonprofit_id: nonprofit['id'], - billing_plan_id: billing_plan_id, - status: 'active' - }) - .timestamps.execute.last + .values({ + nonprofit_id: nonprofit["id"], + billing_plan_id: billing_plan_id, + status: "active" + }) + .timestamps.execute.last # Create the user using the User and Role models (since we have to use Devise) - user = !user ? User.create!(user_data) : user + user = (!user) ? User.create!(user_data) : user role = Qx.insert_into(:roles) - .values(user_id: user.id, name: 'nonprofit_admin', host_id: nonprofit['id'], host_type: 'Nonprofit') - .timestamps - .execute.last + .values(user_id: user.id, name: "nonprofit_admin", host_id: nonprofit["id"], host_type: "Nonprofit") + .timestamps + .execute.last - self.delay.send_onboard_email(nonprofit, nonprofit_data, user_data, extra_info) + delay.send_onboard_email(nonprofit, nonprofit_data, user_data, extra_info) - return { - nonprofit: nonprofit, - user: user, - role: role, - billing_subscription: billing_subscription + { + nonprofit: nonprofit, + user: user, + role: role, + billing_subscription: billing_subscription } end def self.set_nonprofit_defaults(data) - data = data.merge({ + data.merge({ published: true, vetted: Settings.nonprofits_must_be_vetted ? false : true, statement: data[:name][0..16], @@ -114,7 +113,6 @@ def self.set_nonprofit_defaults(data) state_code_slug: Format::Url.convert_to_slug(data[:state_code]), slug: Format::Url.convert_to_slug(data[:name]) }) - data end def self.set_user_defaults(data) @@ -126,22 +124,22 @@ def self.set_user_defaults(data) # user_data and extra_info are additional data hashes sent from the onboarding form def self.send_onboard_email(np, nonprofit_data, user_data, extra_info) # Send the welcome email to the nonprofit - NonprofitMailer.welcome(np['id']).deliver + NonprofitMailer.welcome(np["id"]).deliver # Send an email notifying people internal folks of the new nonporfit, with the above info and extra_info - to_emails = ['support@commitchange.com'] - message = %Q( - New signup on CommitChange for an organization with the name "#{np['name']}" - Location: #{np['city']} #{np['state_code']}, #{np['zip_code']} - Org Email: #{nonprofit_data['email']} - Org Phone: #{nonprofit_data['phone']} - User Email: #{user_data['email']} - User Name: #{user_data['name']} - User Phone: #{user_data['phone']} - Entity Type: #{extra_info['entity_type']} - How they heard about us: #{extra_info['how_they_heard']} - What they want to use: #{['use_donations', 'use_crm', 'use_campaigns', 'use_events'].select{|x| extra_info[x] == 'on'}.join(", ")} + to_emails = ["support@commitchange.com"] + message = %( + New signup on CommitChange for an organization with the name "#{np["name"]}" + Location: #{np["city"]} #{np["state_code"]}, #{np["zip_code"]} + Org Email: #{nonprofit_data["email"]} + Org Phone: #{nonprofit_data["phone"]} + User Email: #{user_data["email"]} + User Name: #{user_data["name"]} + User Phone: #{user_data["phone"]} + Entity Type: #{extra_info["entity_type"]} + How they heard about us: #{extra_info["how_they_heard"]} + What they want to use: #{["use_donations", "use_crm", "use_campaigns", "use_events"].select { |x| extra_info[x] == "on" }.join(", ")} ) - subject = "New Account Signup: #{np['name']}" - GenericMailer.generic_mail('support@commitchange.com', 'CC Bot', message, subject, to_emails, '').deliver + subject = "New Account Signup: #{np["name"]}" + GenericMailer.generic_mail("support@commitchange.com", "CC Bot", message, subject, to_emails, "").deliver end end diff --git a/app/legacy_lib/pay_recurring_donation.rb b/app/legacy_lib/pay_recurring_donation.rb index 1ee1d5cff..066ec94ce 100644 --- a/app/legacy_lib/pay_recurring_donation.rb +++ b/app/legacy_lib/pay_recurring_donation.rb @@ -4,8 +4,6 @@ # require 'delayed_job_helper' module PayRecurringDonation - - # Pay ALL recurring donations that are currently due; each payment gets a queued delayed_job # Returns the number of queued jobs def self.pay_all_due_with_stripe @@ -13,7 +11,7 @@ def self.pay_all_due_with_stripe ids = Psql.execute_vectors( QueryRecurringDonations._all_that_are_due )[1..-1].flatten - + jobs = ids.map do |id| {handler: DelayedJobHelper.create_handler(PayRecurringDonation, :with_stripe, [id])} end @@ -30,7 +28,7 @@ def self.pay_all_due_with_stripe queue: "rec-don-payments" } })) - return ids + ids end # run the payrecurring_donation in development so I can make sure we have the expected failures @@ -58,74 +56,74 @@ def self.pay_all_due_with_stripe # Charge an existing donation via stripe, only if it is due # Pass in an instance of an existing RecurringDonation - def self.with_stripe(rd_id, force_run=false) - ParamValidation.new({:rd_id => rd_id}, { - :rd_id => { - :required => true, - :is_integer=> true - } + def self.with_stripe(rd_id, force_run = false) + ParamValidation.new({rd_id: rd_id}, { + rd_id: { + required: true, + is_integer: true + } }) - rd = RecurringDonation.includes(:misc_recurring_donation_info).where('id = ?', rd_id).first + rd = RecurringDonation.includes(:misc_recurring_donation_info).where("id = ?", rd_id).first unless rd - raise ParamValidation::ValidationError.new("#{rd_id} is not a valid recurring donation", {:key => :rd_id}) + raise ParamValidation::ValidationError.new("#{rd_id} is not a valid recurring donation", {key: :rd_id}) end return false if !force_run && !QueryRecurringDonations.is_due?(rd_id) - donation = Donation.where('id = ?', rd['donation_id']).first + donation = Donation.where("id = ?", rd["donation_id"]).first unless donation - raise ParamValidation::ValidationError.new("#{rd['donation_id']} is not a valid donation", {}) + raise ParamValidation::ValidationError.new("#{rd["donation_id"]} is not a valid donation", {}) end result = {} result = result.merge(InsertDonation.insert_charge({ - 'card_id' => donation['card_id'], - 'recurring_donation' => true, - 'designation' => donation['designation'], - 'amount' => donation['amount'], - 'nonprofit_id' => donation['nonprofit_id'], - 'donation_id' => donation['id'], - 'supporter_id' => donation['supporter_id'], - 'old_donation' => true, - 'fee_covered' => rd.misc_recurring_donation_info&.fee_covered + "card_id" => donation["card_id"], + "recurring_donation" => true, + "designation" => donation["designation"], + "amount" => donation["amount"], + "nonprofit_id" => donation["nonprofit_id"], + "donation_id" => donation["id"], + "supporter_id" => donation["supporter_id"], + "old_donation" => true, + "fee_covered" => rd.misc_recurring_donation_info&.fee_covered })) - if result['charge']['status'] != 'failed' - result['recurring_donation'] = Psql.execute( + if result["charge"]["status"] != "failed" + result["recurring_donation"] = Psql.execute( Qexpr.new.update(:recurring_donations, {n_failures: 0}) - .where("id=$id", id: rd_id).returning('*') + .where("id=$id", id: rd_id).returning("*") ).first - InlineJob::ModernObjectDonationStripeChargeJob.perform_later(donation: donation, legacy_payment: result['payment']) + InlineJob::ModernObjectDonationStripeChargeJob.perform_later(donation: donation, legacy_payment: result["payment"]) - JobQueue.queue(JobTypes::DonationPaymentCreateJob, rd['donation_id'], result['payment']['id']) - InsertActivities.for_recurring_donations([result['payment']['id']]) + JobQueue.queue(JobTypes::DonationPaymentCreateJob, rd["donation_id"], result["payment"]["id"]) + InsertActivities.for_recurring_donations([result["payment"]["id"]]) else - result['recurring_donation'] = Psql.execute( - Qexpr.new.update(:recurring_donations, {n_failures: rd['n_failures'] + 1}) - .where("id=$id", id: rd_id).returning('*') + result["recurring_donation"] = Psql.execute( + Qexpr.new.update(:recurring_donations, {n_failures: rd["n_failures"] + 1}) + .where("id=$id", id: rd_id).returning("*") ).first - DonationMailer.delay.donor_failed_recurring_donation(rd['donation_id']) + DonationMailer.delay.donor_failed_recurring_donation(rd["donation_id"]) rd.reload - if rd['n_failures'] >= 3 - DonationMailer.delay.nonprofit_failed_recurring_donation(rd['donation_id']) + if rd["n_failures"] >= 3 + DonationMailer.delay.nonprofit_failed_recurring_donation(rd["donation_id"]) end - Supporter.find(donation['supporter_id']).supporter_notes.create!(content: "This supporter had a payment failure for their recurring donation with ID #{rd_id}", user: User.find(540)) + Supporter.find(donation["supporter_id"]).supporter_notes.create!(content: "This supporter had a payment failure for their recurring donation with ID #{rd_id}", user: User.find(540)) end - return result + result end - def self.fail_a_recurring_donation(rd, donation, notify_nonprofit=false) + def self.fail_a_recurring_donation(rd, donation, notify_nonprofit = false) recurring_donation = Psql.execute( - Qexpr.new.update(:recurring_donations, {n_failures: 3}) - .where("id=$id", id: rd['id']).returning('*') + Qexpr.new.update(:recurring_donations, {n_failures: 3}) + .where("id=$id", id: rd["id"]).returning("*") ).first - DonationMailer.delay.donor_failed_recurring_donation(rd['donation_id']) + DonationMailer.delay.donor_failed_recurring_donation(rd["donation_id"]) if notify_nonprofit - DonationMailer.delay.nonprofit_failed_recurring_donation(rd['donation_id']) + DonationMailer.delay.nonprofit_failed_recurring_donation(rd["donation_id"]) end - Supporter.find(donation['supporter_id']).supporter_notes.create!(content: "This supporter had a payment failure for their recurring donation with ID #{rd['id']}", user: User.find(540)) - return recurring_donation + Supporter.find(donation["supporter_id"]).supporter_notes.create!(content: "This supporter had a payment failure for their recurring donation with ID #{rd["id"]}", user: User.find(540)) + recurring_donation end end diff --git a/app/legacy_lib/payment_dupes.rb b/app/legacy_lib/payment_dupes.rb index 7c1ba50a5..14b36d901 100644 --- a/app/legacy_lib/payment_dupes.rb +++ b/app/legacy_lib/payment_dupes.rb @@ -1,213 +1,214 @@ module PaymentDupes - def self.copy_dedication(source, target) - return true if source.donation.dedication.blank? - return true if target.donation.dedication.present? && (source.donation.dedication.blank? || target.donation.dedication == source.donation.dedication) - return false if target.donation.dedication.present? - target.donation.dedication = source.donation.dedication - target.donation.save! - end + def self.copy_dedication(source, target) + return true if source.donation.dedication.blank? + return true if target.donation.dedication.present? && (source.donation.dedication.blank? || target.donation.dedication == source.donation.dedication) + return false if target.donation.dedication.present? + target.donation.dedication = source.donation.dedication + target.donation.save! + end - def self.can_copy_dedication?(source, target) - return true if source.donation.dedication.blank? - return true if target.donation.dedication.present? && (source.donation.dedication.blank? || target.donation.dedication == source.donation.dedication) - return false if target.donation.dedication.present? - true - end + def self.can_copy_dedication?(source, target) + return true if source.donation.dedication.blank? + return true if target.donation.dedication.present? && (source.donation.dedication.blank? || target.donation.dedication == source.donation.dedication) + return false if target.donation.dedication.present? + true + end - def self.copy_designation(src, target, designations_to_become_comments) - if designations_to_become_comments.include?(src.donation.designation) - if target.donation&.comment&.include?("Designation: #{src.donation.designation}") - # Already copied, no need to copy again - return true - end - if target.donation.comment.blank? - target.donation.comment = "Designation: " + src.donation.designation - else - target.donation.comment += " \nDesignation: " + src.donation.designation - end - src.donation.designation = nil - target.donation.save! - src.donation.save! - return true - end - return true if src.donation.designation.blank? - return true if target.donation.designation.present? && (src.donation.designation.blank? || target.donation.designation == src.donation.designation) - return false if target.donation.dedication.present? - target.donation.designation = src.donation.designation - target.donation.save! + def self.copy_designation(src, target, designations_to_become_comments) + if designations_to_become_comments.include?(src.donation.designation) + if target.donation&.comment&.include?("Designation: #{src.donation.designation}") + # Already copied, no need to copy again + return true + end + if target.donation.comment.blank? + target.donation.comment = "Designation: " + src.donation.designation + else + target.donation.comment += " \nDesignation: " + src.donation.designation + end + src.donation.designation = nil + target.donation.save! + src.donation.save! + return true end + return true if src.donation.designation.blank? + return true if target.donation.designation.present? && (src.donation.designation.blank? || target.donation.designation == src.donation.designation) + return false if target.donation.dedication.present? + target.donation.designation = src.donation.designation + target.donation.save! + end - def self.can_copy_designation?(src, target, designations_to_become_comments) - if designations_to_become_comments.include?(src.donation.designation) - return true - end - return true if src.donation.designation.blank? - return true if target.donation.designation.present? && (src.donation.designation.blank? || target.donation.designation == src.donation.designation) - return false if target.donation.designation.present? - true + def self.can_copy_designation?(src, target, designations_to_become_comments) + if designations_to_become_comments.include?(src.donation.designation) + return true end + return true if src.donation.designation.blank? + return true if target.donation.designation.present? && (src.donation.designation.blank? || target.donation.designation == src.donation.designation) + return false if target.donation.designation.present? + true + end - def self.copy_comment(source, target, designations_to_become_comments) - return true if source.donation.comment.blank? - return true if target.donation.comment.present? && (source.donation.comment.blank? || target.donation.comment == source.donation.comment) - if target.donation.comment.present? - if designations_to_become_comments.any? { |d| target.donation.comment.include?(d) } - designations_already_copied_to_comment = designations_to_become_comments.select { |d| target.donation.comment.include?(d) } - comment = target.donation.comment - designations_already_copied_to_comment.each do |d| - comment = comment.gsub(" \nDesignation: #{d}", "") - comment = comment.gsub("Designation: #{d}", "") - end - return true if (source.donation.comment.blank? || comment == source.donation.comment) - else - return false - end + def self.copy_comment(source, target, designations_to_become_comments) + return true if source.donation.comment.blank? + return true if target.donation.comment.present? && (source.donation.comment.blank? || target.donation.comment == source.donation.comment) + if target.donation.comment.present? + if designations_to_become_comments.any? { |d| target.donation.comment.include?(d) } + designations_already_copied_to_comment = designations_to_become_comments.select { |d| target.donation.comment.include?(d) } + comment = target.donation.comment + designations_already_copied_to_comment.each do |d| + comment = comment.gsub(" \nDesignation: #{d}", "") + comment = comment.gsub("Designation: #{d}", "") end - target.donation.comment = source.donation.comment - target.donation.save! + return true if source.donation.comment.blank? || comment == source.donation.comment + else + return false + end end + target.donation.comment = source.donation.comment + target.donation.save! + end - def self.can_copy_comment?(source, target, designations_to_become_comments) - return true if source.donation.comment.blank? - return true if target.donation.comment.present? && (source.donation.comment.blank? || target.donation.comment == source.donation.comment) - if target.donation.comment.present? - if designations_to_become_comments.any? { |d| target.donation.comment.include?(d) } - designations_already_copied_to_comment = designations_to_become_comments.select { |d| target.donation.comment.include?(d) } - comment = target.donation.comment - designations_already_copied_to_comment.each do |d| - comment = comment.gsub(" \nDesignation: #{d}", "") - comment = comment.gsub("Designation: #{d}", "") - end - return (source.donation.comment.blank? || comment == source.donation.comment) - else - return false - end + def self.can_copy_comment?(source, target, designations_to_become_comments) + return true if source.donation.comment.blank? + return true if target.donation.comment.present? && (source.donation.comment.blank? || target.donation.comment == source.donation.comment) + if target.donation.comment.present? + if designations_to_become_comments.any? { |d| target.donation.comment.include?(d) } + designations_already_copied_to_comment = designations_to_become_comments.select { |d| target.donation.comment.include?(d) } + comment = target.donation.comment + designations_already_copied_to_comment.each do |d| + comment = comment.gsub(" \nDesignation: #{d}", "") + comment = comment.gsub("Designation: #{d}", "") end - true + return source.donation.comment.blank? || comment == source.donation.comment + else + return false + end end + true + end - def self.remove_payment_dupes(np_id, designations_to_become_comments) - deleted_payments = [] - nonprofit = Nonprofit.find(np_id) - etap_id_cf = CustomFieldMaster.find_by(name: 'E-Tapestry Id #').id - supp = nonprofit.supporters.not_deleted.joins(:custom_field_joins).where( - 'custom_field_joins.custom_field_master_id = ?', etap_id_cf - ).references(:custom_field_joins) + def self.remove_payment_dupes(np_id, designations_to_become_comments) + deleted_payments = [] + nonprofit = Nonprofit.find(np_id) + etap_id_cf = CustomFieldMaster.find_by(name: "E-Tapestry Id #").id + supp = nonprofit.supporters.not_deleted.joins(:custom_field_joins).where( + "custom_field_joins.custom_field_master_id = ?", etap_id_cf + ).references(:custom_field_joins) - supp.find_each do |s| - offsite_payments = s.payments.includes(:donation).where("kind = 'OffsitePayment'").joins(:journal_entries_to_item) - offsite_payments.find_each do |offsite| - # match one offsite donation with an online donation if: - # - the offsite donation was created on the same day that we ran the import and - # - the offsite donation has the same date as the online payment - # - there is a journal entry item for the offsite payment - donation_or_ticket_payments = s.payments.not_matched.includes(:donation).joins( - 'LEFT JOIN nonprofits ON payments.nonprofit_id = nonprofits.id' - ).where( - "(kind = 'Donation' OR kind = 'Ticket' OR kind = 'RecurringDonation') + supp.find_each do |s| + offsite_payments = s.payments.includes(:donation).where("kind = 'OffsitePayment'").joins(:journal_entries_to_item) + offsite_payments.find_each do |offsite| + # match one offsite donation with an online donation if: + # - the offsite donation was created on the same day that we ran the import and + # - the offsite donation has the same date as the online payment + # - there is a journal entry item for the offsite payment + donation_or_ticket_payments = s.payments.not_matched.includes(:donation).joins( + "LEFT JOIN nonprofits ON payments.nonprofit_id = nonprofits.id" + ).where( + "(kind = 'Donation' OR kind = 'Ticket' OR kind = 'RecurringDonation') AND (gross_amount = ? OR net_amount = ?) AND - (to_char(timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', date)), 'YYYY-MM-DD') = ? OR to_char(date, 'YYYY-MM-DD') = ?)", offsite.gross_amount, offsite.gross_amount, offsite.date.strftime('%Y-%m-%d'), offsite.date.strftime('%Y-%m-%d')) - donation_or_ticket_payments.find_each do |online| - reasons = [] - ActiveRecord::Base.transaction do - if online.kind == 'Ticket' - Activity.where(attachment_id: offsite.id, attachment_type: 'Payment').destroy_all - offsite&.offsite_payment&.destroy - offsite.destroy - deleted_payments << offsite.id - if online.payment_dupe_status.present? - online.payment_dupe_status.matched = true - online.payment_dupe_status.matched_with_offline << offsite.id - online.payment_dupe_status.save! - else - online.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [offsite.id]) - end - elsif offsite.donation.event.present? && offsite.donation.event != online.donation.event - # different events, dont delete - elsif offsite.donation.campaign.present? && offsite.donation.campaign != online.donation.campaign - # different campaigns, dont delete - else - unless can_copy_comment?(offsite, online, designations_to_become_comments) - reasons << 'Comment' - end - unless can_copy_dedication?(offsite, online) - reasons << 'Dedication' - end - unless can_copy_designation?(offsite, online, designations_to_become_comments) - reasons << 'Designation' - end - if reasons.none? - if online.kind == 'RecurringDonation' - # addresses all the payments from that recurring donation so we avoid future problems - recurring_donation = online.donation - recurring_payments = recurring_donation.payments - temp_duplicate_payments = [] - temp_offsite_matches = [] - recurring_payments.find_each do |recurring_payment| - equivalent_offsite = s.payments.not_matched.where( - "kind = 'OffsitePayment' AND (gross_amount = ? OR gross_amount = ?) AND (to_char(payments.date, 'YYYY-MM-DD') = ? OR to_char(payments.date, 'YYYY-MM-DD') = ?)", - recurring_payment.gross_amount, recurring_payment.net_amount, recurring_payment.date.in_time_zone(nonprofit.timezone).strftime('%Y-%m-%d'), recurring_payment.date.strftime('%Y-%m-%d') - ).joins(:journal_entries_to_item) - if equivalent_offsite.count == 1 - # match! - temp_offsite_matches << equivalent_offsite.first.id - temp_duplicate_payments << equivalent_offsite.first.id.to_s - if recurring_payment.payment_dupe_status.present? - recurring_payment.payment_dupe_status.matched = true - recurring_payment.payment_dupe_status.matched_with_offline << equivalent_offsite.first.id - recurring_payment.payment_dupe_status.save! - else - recurring_payment.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [equivalent_offsite.first.id]) - end - if equivalent_offsite.first.payment_dupe_status.present? - equivalent_offsite.first.payment_dupe_status.matched = true - equivalent_offsite.first.payment_dupe_status.matched_with_offline << equivalent_offsite.first.id - equivalent_offsite.first.payment_dupe_status.save! - else - equivalent_offsite.first.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [equivalent_offsite.first.id]) - end - end - end - if temp_offsite_matches.any? - # it's the same donation for all of them so - # we can do the copies once - copy_comment(offsite, online, designations_to_become_comments) - copy_dedication(offsite, online) - copy_designation(offsite, online, designations_to_become_comments) - deleted_payments.concat(temp_duplicate_payments) - # deletes matching offsites here - temp_duplicate_payments.each do |op| - op = Payment.find(op) - Activity.where(attachment_id: op.id, attachment_type: 'Payment').destroy_all - op&.offsite_payment&.destroy - op&.donation&.destroy - op&.destroy - end - else - raise ActiveRecord::Rollback - end - else - copy_comment(offsite, online, designations_to_become_comments) - copy_dedication(offsite, online) - copy_designation(offsite, online, designations_to_become_comments) - Activity.where(attachment_id: offsite.id, attachment_type: 'Payment').destroy_all - offsite.donation.destroy - offsite&.offsite_payment&.destroy - offsite.destroy - deleted_payments << offsite.id.to_s - if online.payment_dupe_status.present? - online.payment_dupe_status.matched = true - online.payment_dupe_status.matched_with_offline << offsite.id - online.payment_dupe_status.save! - else - online.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [offsite.id]) - end - end - end - end + (to_char(timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', date)), 'YYYY-MM-DD') = ? OR to_char(date, 'YYYY-MM-DD') = ?)", offsite.gross_amount, offsite.gross_amount, offsite.date.strftime("%Y-%m-%d"), offsite.date.strftime("%Y-%m-%d") + ) + donation_or_ticket_payments.find_each do |online| + reasons = [] + ActiveRecord::Base.transaction do + if online.kind == "Ticket" + Activity.where(attachment_id: offsite.id, attachment_type: "Payment").destroy_all + offsite&.offsite_payment&.destroy + offsite.destroy + deleted_payments << offsite.id + if online.payment_dupe_status.present? + online.payment_dupe_status.matched = true + online.payment_dupe_status.matched_with_offline << offsite.id + online.payment_dupe_status.save! + else + online.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [offsite.id]) + end + elsif offsite.donation.event.present? && offsite.donation.event != online.donation.event + # different events, dont delete + elsif offsite.donation.campaign.present? && offsite.donation.campaign != online.donation.campaign + # different campaigns, dont delete + else + unless can_copy_comment?(offsite, online, designations_to_become_comments) + reasons << "Comment" + end + unless can_copy_dedication?(offsite, online) + reasons << "Dedication" + end + unless can_copy_designation?(offsite, online, designations_to_become_comments) + reasons << "Designation" + end + if reasons.none? + if online.kind == "RecurringDonation" + # addresses all the payments from that recurring donation so we avoid future problems + recurring_donation = online.donation + recurring_payments = recurring_donation.payments + temp_duplicate_payments = [] + temp_offsite_matches = [] + recurring_payments.find_each do |recurring_payment| + equivalent_offsite = s.payments.not_matched.where( + "kind = 'OffsitePayment' AND (gross_amount = ? OR gross_amount = ?) AND (to_char(payments.date, 'YYYY-MM-DD') = ? OR to_char(payments.date, 'YYYY-MM-DD') = ?)", + recurring_payment.gross_amount, recurring_payment.net_amount, recurring_payment.date.in_time_zone(nonprofit.timezone).strftime("%Y-%m-%d"), recurring_payment.date.strftime("%Y-%m-%d") + ).joins(:journal_entries_to_item) + if equivalent_offsite.count == 1 + # match! + temp_offsite_matches << equivalent_offsite.first.id + temp_duplicate_payments << equivalent_offsite.first.id.to_s + if recurring_payment.payment_dupe_status.present? + recurring_payment.payment_dupe_status.matched = true + recurring_payment.payment_dupe_status.matched_with_offline << equivalent_offsite.first.id + recurring_payment.payment_dupe_status.save! + else + recurring_payment.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [equivalent_offsite.first.id]) + end + if equivalent_offsite.first.payment_dupe_status.present? + equivalent_offsite.first.payment_dupe_status.matched = true + equivalent_offsite.first.payment_dupe_status.matched_with_offline << equivalent_offsite.first.id + equivalent_offsite.first.payment_dupe_status.save! + else + equivalent_offsite.first.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [equivalent_offsite.first.id]) + end + end + end + if temp_offsite_matches.any? + # it's the same donation for all of them so + # we can do the copies once + copy_comment(offsite, online, designations_to_become_comments) + copy_dedication(offsite, online) + copy_designation(offsite, online, designations_to_become_comments) + deleted_payments.concat(temp_duplicate_payments) + # deletes matching offsites here + temp_duplicate_payments.each do |op| + op = Payment.find(op) + Activity.where(attachment_id: op.id, attachment_type: "Payment").destroy_all + op&.offsite_payment&.destroy + op&.donation&.destroy + op&.destroy end + else + raise ActiveRecord::Rollback + end + else + copy_comment(offsite, online, designations_to_become_comments) + copy_dedication(offsite, online) + copy_designation(offsite, online, designations_to_become_comments) + Activity.where(attachment_id: offsite.id, attachment_type: "Payment").destroy_all + offsite.donation.destroy + offsite&.offsite_payment&.destroy + offsite.destroy + deleted_payments << offsite.id.to_s + if online.payment_dupe_status.present? + online.payment_dupe_status.matched = true + online.payment_dupe_status.matched_with_offline << offsite.id + online.payment_dupe_status.save! + else + online.payment_dupe_status = PaymentDupeStatus.create!(matched: true, matched_with_offline: [offsite.id]) + end end + end end + end end + end end + end end diff --git a/app/legacy_lib/periodic_report_adapter.rb b/app/legacy_lib/periodic_report_adapter.rb index d8664d71c..8687cc93b 100644 --- a/app/legacy_lib/periodic_report_adapter.rb +++ b/app/legacy_lib/periodic_report_adapter.rb @@ -6,9 +6,8 @@ class PeriodicReportAdapter autoload :FailedRecurringDonationsReport autoload :ActiveRecurringDonationsToCsvReport autoload :StartedRecurringDonationsToCsvReport - - REPORT = 'Report' + REPORT = "Report" private_constant :REPORT class << self diff --git a/app/legacy_lib/periodic_report_adapter/active_recurring_donations_to_csv_report.rb b/app/legacy_lib/periodic_report_adapter/active_recurring_donations_to_csv_report.rb index 245fa1f2e..c906256c3 100644 --- a/app/legacy_lib/periodic_report_adapter/active_recurring_donations_to_csv_report.rb +++ b/app/legacy_lib/periodic_report_adapter/active_recurring_donations_to_csv_report.rb @@ -14,10 +14,10 @@ def run private def params - { nonprofit: nonprofit, nonprofit_s3_key: @nonprofit_s3_key, user: @users.first, filename: @filename} + {nonprofit: nonprofit, nonprofit_s3_key: @nonprofit_s3_key, user: @users.first, filename: @filename} end def nonprofit Nonprofit.find(@nonprofit_id) end -end \ No newline at end of file +end diff --git a/app/legacy_lib/periodic_report_adapter/cancelled_recurring_donations_report.rb b/app/legacy_lib/periodic_report_adapter/cancelled_recurring_donations_report.rb index 8bf16c088..8c65bdae0 100644 --- a/app/legacy_lib/periodic_report_adapter/cancelled_recurring_donations_report.rb +++ b/app/legacy_lib/periodic_report_adapter/cancelled_recurring_donations_report.rb @@ -7,13 +7,13 @@ def initialize(options) end def run - ExportRecurringDonations::initiate_export(@nonprofit_id, params, @user_ids, :cancelled_recurring_donations_automatic_report) + ExportRecurringDonations.initiate_export(@nonprofit_id, params, @user_ids, :cancelled_recurring_donations_automatic_report) end private def params - { :active => false }.merge(period) + {active: false}.merge(period) end def period @@ -22,8 +22,8 @@ def period def last_month { - :cancelled_at_gt_or_eq => (Time.current - 1.month).beginning_of_month, - :cancelled_at_lt => Time.current.beginning_of_month + cancelled_at_gt_or_eq: 1.month.ago.beginning_of_month, + cancelled_at_lt: Time.current.beginning_of_month } end end diff --git a/app/legacy_lib/periodic_report_adapter/failed_recurring_donations_report.rb b/app/legacy_lib/periodic_report_adapter/failed_recurring_donations_report.rb index 46bd3a21b..5de7ba9bd 100644 --- a/app/legacy_lib/periodic_report_adapter/failed_recurring_donations_report.rb +++ b/app/legacy_lib/periodic_report_adapter/failed_recurring_donations_report.rb @@ -7,13 +7,13 @@ def initialize(options) end def run - ExportRecurringDonations::initiate_export(@nonprofit_id, params, @user_ids, :failed_recurring_donations_automatic_report) + ExportRecurringDonations.initiate_export(@nonprofit_id, params, @user_ids, :failed_recurring_donations_automatic_report) end private def params - { :failed => true, :include_last_failed_charge => true }.merge(period) + {failed: true, include_last_failed_charge: true}.merge(period) end def period @@ -22,8 +22,8 @@ def period def last_month { - :from_date => (Time.current - 1.month).beginning_of_month, - :before_date => Time.current.beginning_of_month + from_date: 1.month.ago.beginning_of_month, + before_date: Time.current.beginning_of_month } end end diff --git a/app/legacy_lib/periodic_report_adapter/started_recurring_donations_to_csv_report.rb b/app/legacy_lib/periodic_report_adapter/started_recurring_donations_to_csv_report.rb index 132d0d658..4bce4ad29 100644 --- a/app/legacy_lib/periodic_report_adapter/started_recurring_donations_to_csv_report.rb +++ b/app/legacy_lib/periodic_report_adapter/started_recurring_donations_to_csv_report.rb @@ -13,12 +13,12 @@ def run end private - + def nonprofit Nonprofit.find(@nonprofit_id) end def params - { nonprofit: nonprofit, nonprofit_s3_key: @nonprofit_s3_key, user: @users.first, filename: @filename } + {nonprofit: nonprofit, nonprofit_s3_key: @nonprofit_s3_key, user: @users.first, filename: @filename} end end diff --git a/app/legacy_lib/psql.rb b/app/legacy_lib/psql.rb index a9a18a1a5..496ac8c75 100644 --- a/app/legacy_lib/psql.rb +++ b/app/legacy_lib/psql.rb @@ -2,26 +2,25 @@ # Some convenience wrappers around the postgresql gem, allowing us to avoid activerecord dependency # combine usage of this library with Qexpr -require 'colorize' +require "colorize" -require 'qx' +require "qx" # Initialize the database connection module Psql - # Execute a sql statement (string) def self.execute(statement) - puts statement if ENV['RAILS_ENV'] != 'production' && ENV['RAILS_LOG_LEVEL'] == 'debug' # log to STDOUT on dev/staging - return Qx.execute_raw(raw_expr_str(statement)) + puts statement if ENV["RAILS_ENV"] != "production" && ENV["RAILS_LOG_LEVEL"] == "debug" # log to STDOUT on dev/staging + Qx.execute_raw(raw_expr_str(statement)) end # A variation of execute that returns a vector of vectors rather than a vector of hashes # Useful and faster for creating CSV's def self.execute_vectors(statement) - puts statement if ENV['RAILS_ENV'] != 'production' && ENV['RAILS_LOG_LEVEL'] == 'debug' # log to STDOUT on dev/staging - raw_str = statement.to_s.uncolorize.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') - return Qx.execute_raw(raw_expr_str(statement), format: 'csv') + puts statement if ENV["RAILS_ENV"] != "production" && ENV["RAILS_LOG_LEVEL"] == "debug" # log to STDOUT on dev/staging + statement.to_s.uncolorize.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "") + Qx.execute_raw(raw_expr_str(statement), format: "csv") end def self.transaction(&block) @@ -30,11 +29,10 @@ def self.transaction(&block) end end -private + private # Raw expression string def self.raw_expr_str(statement) - statement.to_s.uncolorize.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') + statement.to_s.uncolorize.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "") end - end diff --git a/app/legacy_lib/qexpr.rb b/app/legacy_lib/qexpr.rb index e8420514a..c5957c1a5 100644 --- a/app/legacy_lib/qexpr.rb +++ b/app/legacy_lib/qexpr.rb @@ -8,21 +8,18 @@ # - composability and reusability of sql fragments # - pretty printing of sql with formatting and color -require 'immutable' -require 'colorize' +require "immutable" +require "colorize" class Qexpr - attr_accessor :tree - - def initialize(h=nil) + def initialize(h = nil) @tree = Immutable::Hash[h] end - def to_s - self.parse + parse end # Parse an qexpr object into a sql string expression @@ -34,12 +31,12 @@ def parse if @tree[:insert] expr = "#{@tree[:insert]} #{@tree[:values].blue}" - expr += "\nRETURNING ".bold.light_blue + (@tree[:returning] || ['id']).join(', ').blue + expr += "\nRETURNING ".bold.light_blue + (@tree[:returning] || ["id"]).join(", ").blue return expr end query_based_expression = @tree[:update] || @tree[:delete_from] || @tree[:select] # Query-based expessions - + if query_based_expression.nil? || query_based_expression.empty? raise ArgumentError.new("Must have a select, update, or delete clause") end @@ -49,9 +46,9 @@ def parse if @tree[:from] expr += "\nFROM".bold.light_blue + @tree[:from].map do |f| f.is_a?(String) ? f : " (#{f[:sub_expr].parse}\n) AS #{f[:as]}" - end.join(', ').blue + end.join(", ").blue end - expr += @tree[:joins].join(' ') if @tree[:joins] + expr += @tree[:joins].join(" ") if @tree[:joins] expr += @tree[:where] if @tree[:where] expr += @tree[:group_by] if @tree[:group_by] expr += @tree[:having] if @tree[:having] @@ -63,38 +60,35 @@ def parse expr = "(#{expr}) AS #{@tree[:as]}" end if @tree[:update] && @tree[:returning] - expr += "\nRETURNING ".bold.light_blue + @tree[:returning].join(', ').blue + expr += "\nRETURNING ".bold.light_blue + @tree[:returning].join(", ").blue end - return expr + expr end - # insert into table_name the values from every hash inside of arr # optionally pass in: # no_timestamps: don't set created_at and updated_at # common_data: a hash of data to set for all rows # returning: what columns to return - def insert(table_name, arr, options={}) + def insert(table_name, arr, options = {}) arr = [arr] if arr.is_a? Hash - arr = arr.map{|h| h.sort.to_h} # Make sure all key/vals are ordered the same way + arr = arr.map { |h| h.sort.to_h } # Make sure all key/vals are ordered the same way keys = arr.first.keys keys = keys.concat(options[:common_data].keys) if options[:common_data] - keys = keys.map{|k| "\"#{k}\""}.join(', ') + keys = keys.map { |k| "\"#{k}\"" }.join(", ") ts_columns = options[:no_timestamps] ? "" : "created_at, updated_at, " ts_values = options[:no_timestamps] ? "" : "#{Qexpr.now}, #{Qexpr.now}, " - common_vals = options[:common_data] ? options[:common_data].values.map{|v| Qexpr.quote(v)} : [] - vals = arr.map{|h| '(' + ts_values + h.values.map{|v| Qexpr.quote(v)}.concat(common_vals).join(',') + ')'}.join(',') + common_vals = options[:common_data] ? options[:common_data].values.map { |v| Qexpr.quote(v) } : [] + vals = arr.map { |h| "(" + ts_values + h.values.map { |v| Qexpr.quote(v) }.concat(common_vals).join(",") + ")" }.join(",") Qexpr.new @tree .put(:insert, "INSERT INTO".bold.light_blue + " #{table_name} (#{ts_columns} #{keys})".blue) .put(:values, "\nVALUES".bold.light_blue + " #{vals}".blue) end - - def update(table_name, settings, os={}) - Qexpr.new @tree.put(:update, "UPDATE".bold.light_blue + " #{table_name}".blue + "\nSET".bold.light_blue + " #{settings.map{|key,val| "#{key.to_s}=#{Qexpr.quote(val)}"}.join(', ')}".blue) + def update(table_name, settings, os = {}) + Qexpr.new @tree.put(:update, "UPDATE".bold.light_blue + " #{table_name}".blue + "\nSET".bold.light_blue + " #{settings.map { |key, val| "#{key}=#{Qexpr.quote(val)}" }.join(", ")}".blue) end - def delete_from(table_name) Qexpr.new @tree.put(:delete_from, "DELETE FROM".bold.light_blue + " #{table_name}".blue) end @@ -102,12 +96,12 @@ def delete_from(table_name) # Create or append select columns def select(*cols) if @tree[:select] - Qexpr.new @tree.put(:select, @tree[:select] + ", #{cols.join(', ')}".blue) + Qexpr.new @tree.put(:select, @tree[:select] + ", #{cols.join(", ")}".blue) else - if cols.count < 4 - cols = " #{cols.join(", ")}" + cols = if cols.count < 4 + " #{cols.join(", ")}" else - cols = "\n #{cols.join("\n, ")}" + "\n #{cols.join("\n, ")}" end Qexpr.new @tree.put(:select, "\nSELECT".bold.light_blue + "#{cols}".blue) end @@ -117,76 +111,71 @@ def select_distinct(*cols) Qexpr.new @tree.put(:select, "\nSELECT DISTINCT".bold.light_blue + "\n #{cols.join("\n, ")}".blue) end - def select_distinct_on(cols_distinct, cols_select) - Qexpr.new @tree.put(:select, "SELECT DISTINCT ON".bold.light_blue + " (#{Array(cols_distinct).join(', ')})\n #{Array(cols_select).join("\n, ")}".blue) + Qexpr.new @tree.put(:select, "SELECT DISTINCT ON".bold.light_blue + " (#{Array(cols_distinct).join(", ")})\n #{Array(cols_select).join("\n, ")}".blue) end - - def from(expr, as=nil) + def from(expr, as = nil) Qexpr.new @tree.put(:from, (@tree[:from] || Immutable::Vector[]).add(Qexpr.from_expr(expr, as))) end - def group_by(*cols) - Qexpr.new @tree.put(:group_by, "\nGROUP BY".bold.light_blue + " #{cols.join(', ')}".blue) + Qexpr.new @tree.put(:group_by, "\nGROUP BY".bold.light_blue + " #{cols.join(", ")}".blue) end - def order_by(expr) - Qexpr.new @tree.put(:order_by, "\nORDER BY".bold.light_blue + " #{expr.to_s}".blue) + Qexpr.new @tree.put(:order_by, "\nORDER BY".bold.light_blue + " #{expr}".blue) end - def limit(i) Qexpr.new @tree.put(:limit, "\nLIMIT".bold.light_blue + " #{i.to_i}".blue) end - def offset(i) Qexpr.new @tree.put(:offset, "\nOFFSET".bold.light_blue + " #{i.to_i}".blue) end - def with(name, expr, materialized:nil) - materialized_text = !materialized.nil? ? (materialized ? "MATERIALIZED" : "NOT MATERIALIZED") : "" - return Qexpr.new( - @tree.put(:withs, - (@tree[:withs] || Immutable::Vector[]).add(name.to_s.blue + " AS #{materialized_text} (\n ".bold.light_blue + " #{expr.is_a?(String) ? expr : expr.parse}".blue + "\n)".bold.light_blue - ) - ) + def with(name, expr, materialized: nil) + materialized_text = if !materialized.nil? + materialized ? "MATERIALIZED" : "NOT MATERIALIZED" + else + "" + end + Qexpr.new( + @tree.put(:withs, + (@tree[:withs] || Immutable::Vector[]).add(name.to_s.blue + " AS #{materialized_text} (\n ".bold.light_blue + " #{expr.is_a?(String) ? expr : expr.parse}".blue + "\n)".bold.light_blue)) ) end - def join(table_name, on_expr, data={}) + def join(table_name, on_expr, data = {}) on_expr = Qexpr.interpolate_expr(on_expr, data) - return Qexpr.new @tree + Qexpr.new @tree .put(:joins, (@tree[:joins] || Immutable::Vector[]).add("\nJOIN".bold.light_blue + " #{table_name}\n ".blue + "ON".bold.light_blue + " #{on_expr}".blue)) end - def inner_join(table_name, on_expr, data={}) + def inner_join(table_name, on_expr, data = {}) on_expr = Qexpr.interpolate_expr(on_expr, data) - return Qexpr.new @tree + Qexpr.new @tree .put(:joins, (@tree[:joins] || Immutable::Vector[]).add("\nINNER JOIN".bold.light_blue + " #{table_name}\n ".blue + "ON".bold.light_blue + " #{on_expr}".blue)) end - def left_outer_join(table_name, on_expr, data={}) + def left_outer_join(table_name, on_expr, data = {}) on_expr = Qexpr.interpolate_expr(on_expr, data) - return Qexpr.new @tree + Qexpr.new @tree .put(:joins, (@tree[:joins] || Immutable::Vector[]).add("\nLEFT OUTER JOIN".bold.light_blue + " #{table_name}\n ".blue + "ON".bold.light_blue + " #{on_expr}".blue)) end - def join_lateral(join_name, select_statement, success_condition=true, data={}) + def join_lateral(join_name, select_statement, success_condition = true, data = {}) select_statement = Qexpr.interpolate_expr(select_statement, data) - return Qexpr.new @tree - .put(:joins, (@tree[:joins] || Immutable::Vector[]).add("\n JOIN LATERAL".bold.light_blue + " (#{select_statement})\n #{join_name} ".blue + "ON".bold.light_blue + " #{success_condition}".blue)) + Qexpr.new @tree + .put(:joins, (@tree[:joins] || Immutable::Vector[]).add("\n JOIN LATERAL".bold.light_blue + " (#{select_statement})\n #{join_name} ".blue + "ON".bold.light_blue + " #{success_condition}".blue)) end - def as(name) - return Qexpr.new @tree.put(:as, name) + Qexpr.new @tree.put(:as, name) end - def where(expr, data={}) + def where(expr, data = {}) expr = Qexpr.interpolate_expr(expr, data) if @tree[:where] Qexpr.new @tree.put(:where, @tree[:where] + "\nAND".bold.light_blue + " (#{expr})".blue) @@ -195,13 +184,11 @@ def where(expr, data={}) end end - def returning(*cols) Qexpr.new @tree.put(:returning, (@tree[:returning] || Immutable::Vector[]).concat(cols)) end - - def having(expr, data={}) + def having(expr, data = {}) if @tree[:having] Qexpr.new @tree.put(:having, @tree[:having] + "\nAND".bold.light_blue + " (#{Qexpr.interpolate_expr(expr, data)})".blue) else @@ -217,7 +204,7 @@ def self.merge_with(qexpr) # Remove clauses from the expression # eg expr.remove(:from, :where) def remove(*keys) - return Qexpr.new keys.reduce(@tree){|tree, key| tree.delete(key)} + Qexpr.new keys.reduce(@tree) { |tree, key| tree.delete(key) } end # Quote a string for use in sql to prevent injection or weird errors @@ -227,19 +214,19 @@ def remove(*keys) def self.quote(val) if val.is_a?(Integer) || (val.is_a?(String) && val =~ /^\$Q\$.+\$Q\$$/) # is a valid num or already quoted val - elsif val == nil + elsif val.nil? "NULL" elsif !!val == val # is a boolean val ? "'t'" : "'f'" else - return "$Q$" + val.to_s + "$Q$" + "$Q$" + val.to_s + "$Q$" end end # An alias of PG.quote_ident, for convenience sake # Double-quotes sql identifiers def self.quote_ident(str) - str.split('.').map{|s| "\"#{s}\""}.join('.') + str.split(".").map { |s| "\"#{s}\"" }.join(".") end # sql-quoted datetime value useful for created_at and updated_at columns @@ -250,7 +237,7 @@ def self.now # Given a max page length and the current page, # return the offset value # (eg: page_length=30 and page=3, then return 60) - def self.page_offset(page_length, page=1) + def self.page_offset(page_length, page = 1) page = page.to_i page = 1 if page <= 0 Qexpr.quote((page.to_i - 1) * page_length.to_i) @@ -258,11 +245,11 @@ def self.page_offset(page_length, page=1) # Given the total row count, the max page length, and the current page, # return the total results left - def self.remaining_count(total_count, page_length, current_page=1) - return 0 unless current_page - rem = total_count.to_i - (current_page.to_i) * page_length.to_i - rem = 0 if rem < 0 - return rem + def self.remaining_count(total_count, page_length, current_page = 1) + return 0 unless current_page + rem = total_count.to_i - current_page.to_i * page_length.to_i + rem = 0 if rem < 0 + rem end # Given a string sql expression with interpolations like "WHERE id > ${id}" @@ -270,16 +257,16 @@ def self.remaining_count(total_count, page_length, current_page=1) # interpolate the hash data into the expression def self.interpolate_expr(expr, data) expr.gsub(/\$\w+/) do |match| - val = data[match.gsub(/[ \$]*/, '').to_sym] + val = data[match.gsub(/[ \$]*/, "").to_sym] if val.is_a?(Array) || val.is_a?(Immutable::Vector) - val.to_a.map{|x| Qexpr.quote(x)}.join(', ') + val.to_a.map { |x| Qexpr.quote(x) }.join(", ") else Qexpr.quote val end end end -private + private # Given some kind of expr object (might be just a string or another whole Qexpr expr), and an 'as' value # then give back either a hash for the sub-Qexpr expression, or just a string. @@ -288,7 +275,7 @@ def self.from_expr(expr, as) if expr.is_a?(Qexpr) Immutable::Hash[sub_expr: expr, as: as] else - " #{expr} #{as ? "AS #{as.to_s}" : ""}" + " #{expr} #{as ? "AS #{as}" : ""}" end end end diff --git a/app/legacy_lib/qexpr_query_chunker.rb b/app/legacy_lib/qexpr_query_chunker.rb index c64b7cd6a..93534b4d8 100644 --- a/app/legacy_lib/qexpr_query_chunker.rb +++ b/app/legacy_lib/qexpr_query_chunker.rb @@ -1,18 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -#TODO combine these two items +# TODO combine these two items module QexprQueryChunker - # Used to get a chunk of a Qexpr query # @param [Integer] offset the offset for the beginning of the chunk # @param [Integer] limit the maximum number of rows to get in the chunk # @param [Boolean] skip_header whether you should skip the header row in the returned output. Defaults to false # @yieldreturn [Qexpr] a block which, when called, returns the main Qexpr query # @return [Enumerator] an Enumerator, with each item an array for a row - def self.get_chunk_of_query(offset=nil, limit=nil, skip_header=false, &block) - Enumerator.new {|y| - - expr = block.call() + def self.get_chunk_of_query(offset = nil, limit = nil, skip_header = false, &block) + Enumerator.new { |y| + expr = block.call if offset expr = expr.offset(offset) end @@ -22,12 +20,12 @@ def self.get_chunk_of_query(offset=nil, limit=nil, skip_header=false, &block) end vecs = Psql.execute_vectors(expr.parse) - if (!skip_header) - y << vecs.first.to_a.map{|k| k.to_s.titleize} + if !skip_header + y << vecs.first.to_a.map { |k| k.to_s.titleize } end - vecs.drop(1).each{|v| y << v.to_a} + vecs.drop(1).each { |v| y << v.to_a } } end @@ -39,23 +37,23 @@ def self.get_chunk_of_query(offset=nil, limit=nil, skip_header=false, &block) # @yieldparam [Boolean] skip_header whether you should skip the header row in the returned output. # @yieldreturn [Enumerator] an Enumerator, with each item an array for a row # @return [Enumerator::Lazy] a lazy enumerator for getting every item in the query - def self.for_export_enumerable(chunk_limit=15000, &block) + def self.for_export_enumerable(chunk_limit = 15000, &block) Enumerator.new do |y| last_export_length = 0 limit = chunk_limit page = 0 - while page == 0 || last_export_length == limit do + while page == 0 || last_export_length == limit # either we haven't started yet or the last export == limit (since if it didn't we're to the end) page += 1 offset = Qexpr.page_offset(limit, page) export_returned = block.call(offset, limit, page > 1).to_a - #we got the titles too if on_first, let's skip one row - last_export_length = page == 1 ? export_returned.length-1 : export_returned.length + # we got the titles too if on_first, let's skip one row + last_export_length = (page == 1) ? export_returned.length - 1 : export_returned.length # efficient? no. Do we care? eh. - export_returned.each {|i| + export_returned.each { |i| y << i } end end.lazy end -end \ No newline at end of file +end diff --git a/app/legacy_lib/query_activities.rb b/app/legacy_lib/query_activities.rb index d1915b60d..5ec25bf47 100644 --- a/app/legacy_lib/query_activities.rb +++ b/app/legacy_lib/query_activities.rb @@ -1,13 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' +require "qx" module QueryActivities def self.for_timeline(nonprofit_id, supporter_id) - Qx.select( "activities.*") + Qx.select("activities.*") .from(:activities) .where("activities.supporter_id = #{supporter_id.to_i} AND activities.nonprofit_id = #{nonprofit_id.to_i}") - .order_by('activities.date DESC') + .order_by("activities.date DESC") .execute end end - diff --git a/app/legacy_lib/query_campaign_gifts.rb b/app/legacy_lib/query_campaign_gifts.rb index 43e5d1320..5dccf9538 100644 --- a/app/legacy_lib/query_campaign_gifts.rb +++ b/app/legacy_lib/query_campaign_gifts.rb @@ -1,33 +1,29 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # Query code for both campaign_gift_options and campaign_gifts -require 'psql' +require "psql" module QueryCampaignGifts - - - # Create a mapping of: { - # 'total_donations' => Integer, # total donations for gift options - # 'total_one_time' => Integer, # total one-time donations for gift option - # 'total_recurring' => Integer, - # 'name' => String, # name of the gift level - # - # Includes the overall sum as well as the donations without gift options - - # NOTE: this doesn't include campaign gift options if they don't have any donations. Why? Bad design, I think. - def self.report_metrics(campaign_id) - - - data = Psql.execute(%Q( + # Create a mapping of: { + # 'total_donations' => Integer, # total donations for gift options + # 'total_one_time' => Integer, # total one-time donations for gift option + # 'total_recurring' => Integer, + # 'name' => String, # name of the gift level + # + # Includes the overall sum as well as the donations without gift options + + # NOTE: this doesn't include campaign gift options if they don't have any donations. Why? Bad design, I think. + def self.report_metrics(campaign_id) + data = Psql.execute(%( SELECT campaign_gift_options.name , COUNT(*) AS total_donations , SUM(ds_one_time.amount) AS total_one_time , SUM(ds_recurring.amount) AS total_recurring FROM (#{donations_for_campaign(campaign_id).parse}) AS ds - LEFT OUTER JOIN (#{get_corresponding_payments(campaign_id, %Q(LEFT OUTER JOIN recurring_donations ON recurring_donations.donation_id = donations.id - ), %Q(WHERE recurring_donations.id IS NULL))}) ds_one_time + LEFT OUTER JOIN (#{get_corresponding_payments(campaign_id, %(LEFT OUTER JOIN recurring_donations ON recurring_donations.donation_id = donations.id + ), %(WHERE recurring_donations.id IS NULL))}) ds_one_time ON ds_one_time.id = ds.id - LEFT OUTER JOIN (#{get_corresponding_payments(campaign_id, %Q(INNER JOIN recurring_donations ON recurring_donations.donation_id = donations.id))}) ds_recurring + LEFT OUTER JOIN (#{get_corresponding_payments(campaign_id, %(INNER JOIN recurring_donations ON recurring_donations.donation_id = donations.id))}) ds_recurring ON ds_recurring.id = ds.id LEFT OUTER JOIN campaign_gifts ON campaign_gifts.donation_id=ds.id @@ -37,16 +33,15 @@ def self.report_metrics(campaign_id) ORDER BY total_donations DESC )) - return {data: data} - end + {data: data} + end - def self.donations_for_campaign(campaign_id) - Qx.select('donations.id, donations.amount').from(:donations).where("campaign_id IN ($ids)", {ids:QueryCampaigns.get_campaign_and_children(campaign_id) - }) - end + def self.donations_for_campaign(campaign_id) + Qx.select("donations.id, donations.amount").from(:donations).where("campaign_id IN ($ids)", {ids: QueryCampaigns.get_campaign_and_children(campaign_id)}) + end - def self.get_corresponding_payments(campaign_id, recurring_clauses, where_clauses="") - %Q(SELECT donations.id, payments.gross_amount AS amount + def self.get_corresponding_payments(campaign_id, recurring_clauses, where_clauses = "") + %(SELECT donations.id, payments.gross_amount AS amount FROM (#{donations_for_campaign(campaign_id).parse}) donations #{recurring_clauses} JOIN LATERAL ( @@ -57,6 +52,5 @@ def self.get_corresponding_payments(campaign_id, recurring_clauses, where_clause ) payments ON true #{where_clauses} ) - end + end end - diff --git a/app/legacy_lib/query_campaign_metrics.rb b/app/legacy_lib/query_campaign_metrics.rb index 69c58f423..33763bbe7 100644 --- a/app/legacy_lib/query_campaign_metrics.rb +++ b/app/legacy_lib/query_campaign_metrics.rb @@ -1,12 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryCampaignMetrics - def self.on_donations(campaign_id) campaign = Campaign.find(campaign_id) result = Psql.execute( Qexpr.new.select("COALESCE(COUNT(DISTINCT donations.id), 0) AS supporters_count", - "COALESCE(SUM(payments.gross_amount), 0) AS total_raised") + "COALESCE(SUM(payments.gross_amount), 0) AS total_raised") .from("campaigns") .join( "donations", "donations.campaign_id=campaigns.id" @@ -15,19 +14,17 @@ def self.on_donations(campaign_id) .where("campaigns.id IN (#{QueryCampaigns .get_campaign_and_children(campaign_id) .parse - })") + })") ).last - return { - 'supporters_count' => result['supporters_count'], - 'total_raised'=> result['total_raised'], - 'goal_amount'=> campaign.goal_amount, - 'show_total_count'=> campaign.show_total_count, - 'show_total_raised'=> campaign.show_total_raised, - 'starting_point' => campaign.starting_point, - 'goal_is_in_supporters' => campaign.goal_is_in_supporters + { + "supporters_count" => result["supporters_count"], + "total_raised" => result["total_raised"], + "goal_amount" => campaign.goal_amount, + "show_total_count" => campaign.show_total_count, + "show_total_raised" => campaign.show_total_raised, + "starting_point" => campaign.starting_point, + "goal_is_in_supporters" => campaign.goal_is_in_supporters } end end - - diff --git a/app/legacy_lib/query_campaigns.rb b/app/legacy_lib/query_campaigns.rb index 64695dade..9dc157adf 100644 --- a/app/legacy_lib/query_campaigns.rb +++ b/app/legacy_lib/query_campaigns.rb @@ -1,66 +1,60 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qexpr' +require "qexpr" module QueryCampaigns - def self.timeline(campaign_id) - ex = QueryCampaigns.payments_expression(campaign_id, true) - ex.group_by("DATE(payments.date)") + ex = QueryCampaigns.payments_expression(campaign_id, true) + ex.group_by("DATE(payments.date)") .order_by("DATE(payments.date)") .execute end - def self.payments_expression(campaign_id, for_timeline) selects = [ - "coalesce(SUM(payments.gross_amount), 0) AS total_cents", - "coalesce(SUM(recurring.gross_amount), 0) AS recurring_cents", - "coalesce(SUM(offsite.gross_amount), 0) AS offsite_cents", - "coalesce(SUM(onetime.gross_amount), 0) AS onetime_cents"] - - for_timeline ? - selects.push("MAX(DATE(payments.date)) AS date") : + "coalesce(SUM(payments.gross_amount), 0) AS total_cents", + "coalesce(SUM(recurring.gross_amount), 0) AS recurring_cents", + "coalesce(SUM(offsite.gross_amount), 0) AS offsite_cents", + "coalesce(SUM(onetime.gross_amount), 0) AS onetime_cents" + ] + + for_timeline ? + selects.push("MAX(DATE(payments.date)) AS date") : selects.push("coalesce(count(supporters.id), 0) AS supporters_count") - return Qx.select(*selects) + Qx.select(*selects) .from("payments") .left_join( ["donations", "payments.donation_id=donations.id"], ["payments AS onetime", "onetime.id=payments.id AND onetime.kind='Donation'"], ["payments AS offsite", "offsite.id=payments.id AND offsite.kind='OffsitePayment'"], - ["payments AS recurring", "recurring.id=payments.id AND recurring.kind='RecurringDonation'"]) + ["payments AS recurring", "recurring.id=payments.id AND recurring.kind='RecurringDonation'"] + ) .where("donations.campaign_id IN (#{QueryCampaigns.get_campaign_and_children(campaign_id).parse})") end - def self.totals(campaign_id) - ex = QueryCampaigns.payments_expression(campaign_id, false) - ex.add_left_join(["supporters", "donations.supporter_id=supporters.id"]) + ex = QueryCampaigns.payments_expression(campaign_id, false) + ex.add_left_join(["supporters", "donations.supporter_id=supporters.id"]) .execute.first end - def self.name_and_id(npo_id) - np = Nonprofit.find(npo_id) - campaigns = np.campaigns.not_deleted.includes(:profile).order('campaigns.name ASC') - output = campaigns.map do |i| + campaigns = np.campaigns.not_deleted.includes(:profile).order("campaigns.name ASC") + campaigns.map do |i| { - 'name' => i.name, - 'id' => i.id, - 'isChildCampaign' => i.child_campaign?, - 'creator' => i.profile&.name || "user ##{i.profile.id}" + "name" => i.name, + "id" => i.id, + "isChildCampaign" => i.child_campaign?, + "creator" => i.profile&.name || "user ##{i.profile.id}" } end - output end def self.get_campaign_and_children(campaign_id) Qx.select("id") - .from('campaigns') - .where("campaigns.id = $id OR campaigns.parent_campaign_id=$id", - id: campaign_id) + .from("campaigns") + .where("campaigns.id = $id OR campaigns.parent_campaign_id=$id", + id: campaign_id) end - - end diff --git a/app/legacy_lib/query_charges.rb b/app/legacy_lib/query_charges.rb index 0f6c60198..95d244e90 100644 --- a/app/legacy_lib/query_charges.rb +++ b/app/legacy_lib/query_charges.rb @@ -1,4 +1,4 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'psql' +require "psql" module QueryCharges end diff --git a/app/legacy_lib/query_donations.rb b/app/legacy_lib/query_donations.rb index 78c4e8e55..324376480 100644 --- a/app/legacy_lib/query_donations.rb +++ b/app/legacy_lib/query_donations.rb @@ -1,53 +1,51 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryDonations - # Export all donation data for a given campaign - def self.campaign_export(campaign_id) + def self.campaign_export(campaign_id) Psql.execute_vectors( Qexpr.new.select([ - 'donations.created_at', - '(payments.gross_amount/100.00)::money::text AS amount', - "COUNT(recurring_donations.id) > 0 AS recurring", - "STRING_AGG(campaign_gift_options.name, ',') AS campaign_gift_names" + "donations.created_at", + "(payments.gross_amount/100.00)::money::text AS amount", + "COUNT(recurring_donations.id) > 0 AS recurring", + "STRING_AGG(campaign_gift_options.name, ',') AS campaign_gift_names" ].concat(QuerySupporters.supporter_export_selections) .concat([ - "supporters.id AS \"Supporter ID\"", + "supporters.id AS \"Supporter ID\"" ]).concat([ - "coalesce(donations.designation, 'None') AS designation", - "#{QueryPayments.get_dedication_or_empty('type')}::text AS \"Dedication Type\"", - "#{QueryPayments.get_dedication_or_empty('name')}::text AS \"Dedicated To: Name\"", - "#{QueryPayments.get_dedication_or_empty('supporter_id')}::text AS \"Dedicated To: Supporter ID\"", - "#{QueryPayments.get_dedication_or_empty('contact', 'email')}::text AS \"Dedicated To: Email\"", - "#{QueryPayments.get_dedication_or_empty('contact', "phone")}::text AS \"Dedicated To: Phone\"", - "#{QueryPayments.get_dedication_or_empty( "contact", "address")}::text AS \"Dedicated To: Address\"", - "#{QueryPayments.get_dedication_or_empty( "note")}::text AS \"Dedicated To: Note\"", - "donations.campaign_id AS \"Campaign Id\"", - "users.email AS \"Campaign Creator Email\"" - ]) - ).from(:donations) + "coalesce(donations.designation, 'None') AS designation", + "#{QueryPayments.get_dedication_or_empty("type")}::text AS \"Dedication Type\"", + "#{QueryPayments.get_dedication_or_empty("name")}::text AS \"Dedicated To: Name\"", + "#{QueryPayments.get_dedication_or_empty("supporter_id")}::text AS \"Dedicated To: Supporter ID\"", + "#{QueryPayments.get_dedication_or_empty("contact", "email")}::text AS \"Dedicated To: Email\"", + "#{QueryPayments.get_dedication_or_empty("contact", "phone")}::text AS \"Dedicated To: Phone\"", + "#{QueryPayments.get_dedication_or_empty("contact", "address")}::text AS \"Dedicated To: Address\"", + "#{QueryPayments.get_dedication_or_empty("note")}::text AS \"Dedicated To: Note\"", + "donations.campaign_id AS \"Campaign Id\"", + "users.email AS \"Campaign Creator Email\"" + ])).from(:donations) .join(:supporters, "supporters.id=donations.supporter_id") .left_outer_join(:campaign_gifts, "campaign_gifts.donation_id=donations.id") .left_outer_join(:campaign_gift_options, "campaign_gift_options.id=campaign_gifts.campaign_gift_option_id") .left_outer_join(:recurring_donations, "recurring_donations.donation_id = donations.id") .join_lateral(:payments, - get_first_payment_for_donation.parse, true) - .join(Qx.select('id, profile_id').from('campaigns') + get_first_payment_for_donation.parse, true) + .join(Qx.select("id, profile_id").from("campaigns") .where("id IN (#{QueryCampaigns .get_campaign_and_children(campaign_id) - .parse})").as('campaigns').parse, - 'donations.campaign_id=campaigns.id') - .join(Qx.select('users.id, profiles.id AS profiles_id, users.email') - .from('users') - .add_join('profiles', 'profiles.user_id = users.id') + .parse})").as("campaigns").parse, + "donations.campaign_id=campaigns.id") + .join(Qx.select("users.id, profiles.id AS profiles_id, users.email") + .from("users") + .add_join("profiles", "profiles.user_id = users.id") .as("users").parse, "users.profiles_id=campaigns.profile_id") .group_by("donations.id", "supporters.id", "payments.id", "payments.gross_amount", "users.email") .order_by("donations.date") ) - end + end def self.for_campaign_activities(id) - QueryDonations.activities_expression(['donations.recurring']) + QueryDonations.activities_expression(["donations.recurring"]) .where("donations.campaign_id IN (#{QueryCampaigns .get_campaign_and_children(id) .parse})") @@ -56,29 +54,28 @@ def self.for_campaign_activities(id) def self.activities_expression(additional_selects) selects = [" - CASE + CASE WHEN donations.anonymous='t' - OR supporters.anonymous='t' - OR supporters.name='' - OR supporters.name IS NULL - THEN 'A supporter' - ELSE supporters.name - END AS supporter_name", - "(donations.amount / 100.0)::money::text as amount", - "donations.date"] + (additional_selects ? additional_selects : []) + OR supporters.anonymous='t' + OR supporters.name='' + OR supporters.name IS NULL + THEN 'A supporter' + ELSE supporters.name + END AS supporter_name", + "(donations.amount / 100.0)::money::text as amount", + "donations.date"] + (additional_selects || []) - return Qx.select(selects.join(',')) + Qx.select(selects.join(",")) .from(:donations) - .left_join(:supporters, 'donations.supporter_id=supporters.id') + .left_join(:supporters, "donations.supporter_id=supporters.id") .order_by("donations.date desc") .limit(15) end - def self.get_first_payment_for_donation(table_selector='donations') - Qx.select('payments.id, payments.gross_amount').from(:payments) - .where("payments.donation_id = #{table_selector}.id") - .order_by('payments.created_at ASC') - .limit(1) + def self.get_first_payment_for_donation(table_selector = "donations") + Qx.select("payments.id, payments.gross_amount").from(:payments) + .where("payments.donation_id = #{table_selector}.id") + .order_by("payments.created_at ASC") + .limit(1) end - end diff --git a/app/legacy_lib/query_email_settings.rb b/app/legacy_lib/query_email_settings.rb index 2d1c41715..b980bedcb 100644 --- a/app/legacy_lib/query_email_settings.rb +++ b/app/legacy_lib/query_email_settings.rb @@ -1,10 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryEmailSettings - - Settings = ['notify_payments', 'notify_campaigns', 'notify_events', 'notify_payouts', 'notify_recurring_donations'] + Settings = ["notify_payments", "notify_campaigns", "notify_events", "notify_payouts", "notify_recurring_donations"] def self.fetch(np_id, user_id) - es = Psql.execute(%Q( + es = Psql.execute(%( SELECT * FROM email_settings WHERE nonprofit_id=#{Qexpr.quote(np_id.to_i)} @@ -13,14 +12,16 @@ def self.fetch(np_id, user_id) # If the user's event_settings table does not exist, return a hash with all settings true if es.nil? - es = Psql.execute(%Q( + es = Psql.execute(%( SELECT column_name FROM information_schema.columns WHERE table_name='email_settings' - )).map{|h| h['column_name']} - .reject{|name| ['id', 'nonprofit_id', 'user_id'].include?(name)} - .reduce({}){|h, name| h[name] = true; h} + )).map { |h| h["column_name"] } + .reject { |name| ["id", "nonprofit_id", "user_id"].include?(name) } + .each_with_object({}) { |name, h| + h[name] = true + } end - return es + es end end diff --git a/app/legacy_lib/query_event_discounts.rb b/app/legacy_lib/query_event_discounts.rb index 1ab648a77..c7e957406 100644 --- a/app/legacy_lib/query_event_discounts.rb +++ b/app/legacy_lib/query_event_discounts.rb @@ -1,15 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryEventDiscounts - def self.with_event_ids(event_ids) return [] if event_ids.empty? - x = Psql.execute( + Psql.execute( Qexpr.new.select("name", "id", "percent", "code", "created_at") .from("event_discounts") .where("event_discounts.event_id IN ($ids)", ids: event_ids) - .order_by("created_at DESC"), - ).map{|h| HashWithIndifferentAccess.new(h)} - - end - + .order_by("created_at DESC") + ).map { |h| ActiveSupport::HashWithIndifferentAccess.new(h) } + end end diff --git a/app/legacy_lib/query_event_metrics.rb b/app/legacy_lib/query_event_metrics.rb index 5d5556854..f4da6aabd 100644 --- a/app/legacy_lib/query_event_metrics.rb +++ b/app/legacy_lib/query_event_metrics.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryEventMetrics - - def self.expression(additional_selects=[]) + def self.expression(additional_selects = []) selects = [ "coalesce(tickets.total, 0) AS total_attendees", "coalesce(tickets.checked_in_count, 0) AS checked_in_count", @@ -14,7 +13,7 @@ def self.expression(additional_selects=[]) .from("tickets") .group_by("event_id") .as("tickets") - + ticket_payments_subquery = Qx.select("payment_id", "MAX(event_id) AS event_id").from("tickets").group_by("payment_id").as("tickets") ticket_payments_sub = Qx.select("SUM(payments.gross_amount) AS total_paid", "tickets.event_id") @@ -30,9 +29,9 @@ def self.expression(additional_selects=[]) .as("donations") selects = selects.concat(additional_selects) - return Qx.select(*selects) - .from("events") - .left_join( + Qx.select(*selects) + .from("events") + .left_join( [tickets_sub, "tickets.event_id = events.id"], [donations_sub, "donations.event_id = events.id"], [ticket_payments_sub, "ticket_payments.event_id=events.id"] @@ -41,49 +40,47 @@ def self.expression(additional_selects=[]) def self.with_event_ids(event_ids) return [] if event_ids.empty? - QueryEventMetrics.expression().where("events.id in ($ids)", ids: event_ids).execute + QueryEventMetrics.expression.where("events.id in ($ids)", ids: event_ids).execute end def self.for_listings(id_type, id, params) selects = [ - 'events.id', - 'events.name', - 'events.venue_name', - 'events.address', - 'events.city', - 'events.state_code', - 'events.zip_code', - 'events.start_datetime', - 'events.end_datetime', - 'events.organizer_email' + "events.id", + "events.name", + "events.venue_name", + "events.address", + "events.city", + "events.state_code", + "events.zip_code", + "events.start_datetime", + "events.end_datetime", + "events.organizer_email" ] exp = QueryEventMetrics.expression(selects) - if id_type == 'profile' + if id_type == "profile" exp = exp.and_where(["events.profile_id = $id", id: id]) end - if id_type == 'nonprofit' + if id_type == "nonprofit" exp = exp.and_where(["events.nonprofit_id = $id", id: id]) end - if params['active'].present? + if params["active"].present? exp = exp - .and_where(['events.end_datetime >= $date', date: Time.now]) + .and_where(["events.end_datetime >= $date", date: Time.now]) .and_where(["events.published = TRUE AND coalesce(events.deleted, FALSE) = FALSE"]) end - if params['past'].present? + if params["past"].present? exp = exp - .and_where(['events.end_datetime < $date', date: Time.now]) + .and_where(["events.end_datetime < $date", date: Time.now]) .and_where(["events.published = TRUE AND coalesce(events.deleted, FALSE) = FALSE"]) end - if params['unpublished'].present? + if params["unpublished"].present? exp = exp.and_where(["coalesce(events.published, FALSE) = FALSE AND coalesce(events.deleted, FALSE) = FALSE"]) end - if params['deleted'].present? + if params["deleted"].present? exp = exp.and_where(["events.deleted = TRUE"]) end - return exp.execute + exp.execute end - end - diff --git a/app/legacy_lib/query_event_organizer.rb b/app/legacy_lib/query_event_organizer.rb index c70507b1d..521ee63f1 100644 --- a/app/legacy_lib/query_event_organizer.rb +++ b/app/legacy_lib/query_event_organizer.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryEventOrganizer - def self.with_event(event_id) + def self.with_event(event_id) Qx.select( - "coalesce(profiles.name, nonprofits.name) AS name", - "coalesce(users.email, nonprofits.email) AS email" - ) + "coalesce(profiles.name, nonprofits.name) AS name", + "coalesce(users.email, nonprofits.email) AS email" + ) .from(:events) .left_join(:profiles, "profiles.id=events.profile_id") .add_left_join(:users, "profiles.user_id=users.id") .add_join(:nonprofits, "events.nonprofit_id=nonprofits.id") .where("events.id=$id", id: event_id) .execute.first - end + end end diff --git a/app/legacy_lib/query_full_contact_infos.rb b/app/legacy_lib/query_full_contact_infos.rb index 1d3a71ee9..029e9fbf9 100644 --- a/app/legacy_lib/query_full_contact_infos.rb +++ b/app/legacy_lib/query_full_contact_infos.rb @@ -1,14 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - module QueryFullContactInfos - def self.fetch_associated_tables(fc_info_id) - photo = Psql.execute( Qexpr.new.from(:full_contact_photos).select('url').where("full_contact_info_id = $id", id: fc_info_id).where("is_primary")) - orgs = Psql.execute( Qexpr.new.from(:full_contact_orgs).select('current', 'name', 'title', 'start_date', 'end_date').where("full_contact_info_id = $id", id: fc_info_id).order_by('start_date DESC NULLS LAST')) - topics = Psql.execute( Qexpr.new.from(:full_contact_topics).select('value').where("full_contact_info_id = $id", id: fc_info_id).order_by('value ASC')) - profiles = Psql.execute( Qexpr.new.from(:full_contact_social_profiles).select('type_id', 'followers', 'url').where("full_contact_info_id = $id", id: fc_info_id).order_by('type_id ASC')) - return { + photo = Psql.execute(Qexpr.new.from(:full_contact_photos).select("url").where("full_contact_info_id = $id", id: fc_info_id).where("is_primary")) + orgs = Psql.execute(Qexpr.new.from(:full_contact_orgs).select("current", "name", "title", "start_date", "end_date").where("full_contact_info_id = $id", id: fc_info_id).order_by("start_date DESC NULLS LAST")) + topics = Psql.execute(Qexpr.new.from(:full_contact_topics).select("value").where("full_contact_info_id = $id", id: fc_info_id).order_by("value ASC")) + profiles = Psql.execute(Qexpr.new.from(:full_contact_social_profiles).select("type_id", "followers", "url").where("full_contact_info_id = $id", id: fc_info_id).order_by("type_id ASC")) + { photo: photo, topics: topics, orgs: orgs, diff --git a/app/legacy_lib/query_nonprofit_keys.rb b/app/legacy_lib/query_nonprofit_keys.rb index d751f9aeb..b74746c8a 100644 --- a/app/legacy_lib/query_nonprofit_keys.rb +++ b/app/legacy_lib/query_nonprofit_keys.rb @@ -1,12 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - module QueryNonprofitKeys - def self.get_key(npo_id, key_name) item = Nonprofit.find(npo_id).nonprofit_key&.send(key_name.to_sym) raise ActiveRecord::RecordNotFound.new("Nonprofit key does not exist: #{key_name}") unless item - item + item end - end diff --git a/app/legacy_lib/query_nonprofits.rb b/app/legacy_lib/query_nonprofits.rb index 83b150b40..9d8b009bf 100644 --- a/app/legacy_lib/query_nonprofits.rb +++ b/app/legacy_lib/query_nonprofits.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryNonprofits - # def self.all_that_need_payouts # Psql.execute_vectors( # Qexpr.new.select( @@ -35,92 +34,93 @@ def self.by_search_string(string) .limit(10) )[1..-1] if results - results = results.map {|id, name| {id: id, name: name}} + results = results.map { |id, name| {id: id, name: name} } end - return results + results end def self.for_admin(params) expr = Qx.select( - 'nonprofits.id', - 'nonprofits.name', - 'nonprofits.email', - 'nonprofits.state_code', - 'nonprofits.created_at::date::text AS created_at', - 'nonprofits.vetted', - 'nonprofits.houid', - 'nonprofits.stripe_account_id', - 'coalesce(events.count, 0) AS events_count', - 'coalesce(campaigns.count, 0) AS campaigns_count', - 'billing_plans.percentage_fee', - 'cards.stripe_customer_id', - 'charges.total_processed', - 'charges.total_fees' + "nonprofits.id", + "nonprofits.name", + "nonprofits.email", + "nonprofits.state_code", + "nonprofits.created_at::date::text AS created_at", + "nonprofits.vetted", + "nonprofits.houid", + "nonprofits.stripe_account_id", + "coalesce(events.count, 0) AS events_count", + "coalesce(campaigns.count, 0) AS campaigns_count", + "billing_plans.percentage_fee", + "cards.stripe_customer_id", + "charges.total_processed", + "charges.total_fees" ).from(:nonprofits) - .add_left_join(:stripe_accounts, "nonprofits.stripe_account_id=stripe_accounts.stripe_account_id") - .add_left_join(:cards, "cards.holder_id=nonprofits.id AND cards.holder_type='Nonprofit'") - .add_left_join(:billing_subscriptions, "billing_subscriptions.nonprofit_id=nonprofits.id") - .add_left_join(:billing_plans, "billing_subscriptions.billing_plan_id=billing_plans.id") - .add_left_join( - Qx.select( - "((SUM(coalesce(fee, 0)) * .978) / 100)::money::text AS total_fees", - "(SUM(coalesce(amount, 0)) / 100)::money::text AS total_processed", - "nonprofit_id") - .from(:charges) - .where("status != 'failed'") - .and_where("created_at::date >= '2017-03-15'") - .group_by("nonprofit_id") - .as("charges"), - "charges.nonprofit_id=nonprofits.id" - ) - .add_left_join( - Qx.select("COUNT(id)", "nonprofit_id") - .from(:events) - .group_by("nonprofit_id") - .as("events"), - "events.nonprofit_id=nonprofits.id" - ) - .add_left_join( - Qx.select("COUNT(id)", "nonprofit_id") - .from(:campaigns) - .group_by("nonprofit_id") - .as("campaigns"), - "campaigns.nonprofit_id=nonprofits.id" - ) - .paginate(params[:page].to_i, params[:page_length].to_i) - .order_by('nonprofits.created_at DESC') + .add_left_join(:stripe_accounts, "nonprofits.stripe_account_id=stripe_accounts.stripe_account_id") + .add_left_join(:cards, "cards.holder_id=nonprofits.id AND cards.holder_type='Nonprofit'") + .add_left_join(:billing_subscriptions, "billing_subscriptions.nonprofit_id=nonprofits.id") + .add_left_join(:billing_plans, "billing_subscriptions.billing_plan_id=billing_plans.id") + .add_left_join( + Qx.select( + "((SUM(coalesce(fee, 0)) * .978) / 100)::money::text AS total_fees", + "(SUM(coalesce(amount, 0)) / 100)::money::text AS total_processed", + "nonprofit_id" + ) + .from(:charges) + .where("status != 'failed'") + .and_where("created_at::date >= '2017-03-15'") + .group_by("nonprofit_id") + .as("charges"), + "charges.nonprofit_id=nonprofits.id" + ) + .add_left_join( + Qx.select("COUNT(id)", "nonprofit_id") + .from(:events) + .group_by("nonprofit_id") + .as("events"), + "events.nonprofit_id=nonprofits.id" + ) + .add_left_join( + Qx.select("COUNT(id)", "nonprofit_id") + .from(:campaigns) + .group_by("nonprofit_id") + .as("campaigns"), + "campaigns.nonprofit_id=nonprofits.id" + ) + .paginate(params[:page].to_i, params[:page_length].to_i) + .order_by("nonprofits.created_at DESC") - if params[:search].present? - expr = expr.where(%Q( + if params[:search].present? + expr = expr.where(%( nonprofits.name ILIKE $search OR nonprofits.email ILIKE $search OR nonprofits.city ILIKE $search OR nonprofits.id = $id - ), search: '%' + params[:search] + '%', id: params[:search].to_i) - end + ), search: "%" + params[:search] + "%", id: params[:search].to_i) + end - results = expr.execute - results.map do |i| + results = expr.execute + results.map do |i| np = Nonprofit.includes(:stripe_account).find(i["id"]) - if np.stripe_account - i['verification_status'] = np.stripe_account.verification_status + i["verification_status"] = if np.stripe_account + np.stripe_account.verification_status else - i['verification_status'] = :unverified + :unverified end i end end - def self.find_nonprofits_with_no_payments() - Nonprofit.includes(:payments).where('payments.nonprofit_id IS NULL') + def self.find_nonprofits_with_no_payments + Nonprofit.includes(:payments).where("payments.nonprofit_id IS NULL") end def self.find_nonprofits_with_payments_in_last_n_days(days) - Payment.where("date >= ?", Time.now - days.days).pluck('nonprofit_id').to_a.uniq + Payment.where("date >= ?", Time.now - days.days).pluck("nonprofit_id").to_a.uniq end def self.find_nonprofits_with_payments_but_not_in_last_n_days(days) recent_nonprofits = find_nonprofits_with_payments_in_last_n_days(days) - Payment.where("date < ?", Time.now - days.days).pluck('nonprofit_id').to_a.uniq.select{|i| !recent_nonprofits.include?(i)} + Payment.where("date < ?", Time.now - days.days).pluck("nonprofit_id").to_a.uniq.select { |i| !recent_nonprofits.include?(i) } end end diff --git a/app/legacy_lib/query_payments.rb b/app/legacy_lib/query_payments.rb index 62348b58e..86a5d2c6e 100644 --- a/app/legacy_lib/query_payments.rb +++ b/app/legacy_lib/query_payments.rb @@ -1,8 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryPayments - - def self.get_nonprofit_query(npo_id) Qexpr.new.select("*").from(:nonprofits).where("id = $id", id: npo_id).limit(1) end @@ -23,63 +21,60 @@ def self.get_nonprofit_payments_query(npo_id) # * For refunds and disputes, the gross_amount should be negative since we're decreasing the nonprofit's balance # # In effect, we're getting the list of payments which haven't been paid out in a some fashion. This is not a great design but it works mostly. - def self.ids_for_payout(npo_id, options={}) - end_of_day = (Time.current + 1.day).beginning_of_day - Qx.select('DISTINCT payments.id') - .from(:payments) - .left_join(:charges, 'charges.payment_id=payments.id') - .add_left_join(:refunds, 'refunds.payment_id=payments.id') - .add_left_join(:dispute_transactions, 'dispute_transactions.payment_id=payments.id') - .add_left_join(:manual_balance_adjustments, "manual_balance_adjustments.payment_id=payments.id") - .where('payments.nonprofit_id=$id', id: npo_id) - .and_where("refunds.payment_id IS NOT NULL OR charges.payment_id IS NOT NULL OR dispute_transactions.payment_id IS NOT NULL OR manual_balance_adjustments.payment_id IS NOT NULL") - .and_where(%Q( + def self.ids_for_payout(npo_id, options = {}) + end_of_day = 1.day.from_now.beginning_of_day + Qx.select("DISTINCT payments.id") + .from(:payments) + .left_join(:charges, "charges.payment_id=payments.id") + .add_left_join(:refunds, "refunds.payment_id=payments.id") + .add_left_join(:dispute_transactions, "dispute_transactions.payment_id=payments.id") + .add_left_join(:manual_balance_adjustments, "manual_balance_adjustments.payment_id=payments.id") + .where("payments.nonprofit_id=$id", id: npo_id) + .and_where("refunds.payment_id IS NOT NULL OR charges.payment_id IS NOT NULL OR dispute_transactions.payment_id IS NOT NULL OR manual_balance_adjustments.payment_id IS NOT NULL") + .and_where(%( ((refunds.payment_id IS NOT NULL AND refunds.disbursed IS NULL) OR refunds.disbursed='f') OR (charges.status='available') OR (dispute_transactions.disbursed='f' OR (NOT manual_balance_adjustments.disbursed)) )) - .and_where("payments.date <= $date", date: options[:date] || end_of_day) - .execute.map{|h| h['id']} + .and_where("payments.date <= $date", date: options[:date] || end_of_day) + .execute.map { |h| h["id"] } end # the amount to payout calculates the total payout based upon the payments it's provided, likely provided from ids_to_payout def self.get_payout_totals(payment_ids) - return {'gross_amount' => 0, 'fee_total' => 0, 'net_amount' => 0} if payment_ids.empty? + return {"gross_amount" => 0, "fee_total" => 0, "net_amount" => 0} if payment_ids.empty? Qx.select( - 'SUM(payments.gross_amount) AS gross_amount', - 'SUM(payments.fee_total) AS fee_total', - 'SUM(payments.net_amount) AS net_amount', - 'COUNT(payments.*) AS count') + "SUM(payments.gross_amount) AS gross_amount", + "SUM(payments.fee_total) AS fee_total", + "SUM(payments.net_amount) AS net_amount", + "COUNT(payments.*) AS count" + ) .from(:payments) .where("payments.id IN ($ids)", ids: payment_ids) .execute.first end - - - def self.nonprofit_balances(npo_id) payout_totals = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(npo_id)) - + pending = Nonprofit.find(npo_id).payments.pending_totals { - 'available' => {'net' => payout_totals['net_amount'] || 0, 'gross' => payout_totals['gross_amount'] || 0}, - 'pending' => {'net' => pending['net'] || 0, 'gross' => pending['gross'] || 0} - } + "available" => {"net" => payout_totals["net_amount"] || 0, "gross" => payout_totals["gross_amount"] || 0}, + "pending" => {"net" => pending["net"] || 0, "gross" => pending["gross"] || 0} + } end - def self.full_search(npo_id, query) limit = 30 offset = Qexpr.page_offset(limit, query[:page]) expr = full_search_expr(npo_id, query).select( - 'payments.kind', - 'payments.towards', - 'payments.id AS id', - 'supporters.name', - 'supporters.email', - 'payments.gross_amount', + "payments.kind", + "payments.towards", + "payments.id AS id", + "supporters.name", + "supporters.email", + "payments.gross_amount", 'timezone( COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', payments.date) @@ -92,121 +87,118 @@ def self.full_search(npo_id, query) .remove(:select) .remove(:order_by) .select( - 'COALESCE(COUNT(payments.id), 0) AS count', - 'COALESCE((SUM(payments.gross_amount) / 100.0), 0)::money::text AS amount') + "COALESCE(COUNT(payments.id), 0) AS count", + "COALESCE((SUM(payments.gross_amount) / 100.0), 0)::money::text AS amount" + ) totals = Psql.execute(totals_query).first - return { + { data: payments, - total_count: totals['count'], - total_amount: totals['amount'], - remaining: Qexpr.remaining_count(totals['count'], limit, query[:page]) + total_count: totals["count"], + total_amount: totals["amount"], + remaining: Qexpr.remaining_count(totals["count"], limit, query[:page]) } - end - # we must provide payments.*, supporters.*, donations.*, associated event_id, associated campaign_id def self.full_search_expr(npo_id, query) - expr = Qexpr.new.from('payments') - .inner_join('supporters', "supporters.id=payments.supporter_id") - .inner_join('nonprofits', 'nonprofits.id=payments.nonprofit_id') - .left_outer_join('donations', 'donations.id=payments.donation_id' ) - .join("(#{select_to_filter_search(npo_id, query)}) AS \"filtered_payments\"", 'payments.id = filtered_payments.id') - .order_by('payments.date DESC') - - if ['asc', 'desc'].include? query[:sort_amount] + expr = Qexpr.new.from("payments") + .inner_join("supporters", "supporters.id=payments.supporter_id") + .inner_join("nonprofits", "nonprofits.id=payments.nonprofit_id") + .left_outer_join("donations", "donations.id=payments.donation_id") + .join("(#{select_to_filter_search(npo_id, query)}) AS \"filtered_payments\"", "payments.id = filtered_payments.id") + .order_by("payments.date DESC") + + if ["asc", "desc"].include? query[:sort_amount] expr = expr.order_by("payments.gross_amount #{query[:sort_amount]}") end - if ['asc', 'desc'].include? query[:sort_date] + if ["asc", "desc"].include? query[:sort_date] expr = expr.order_by("payments.date #{query[:sort_date]}") end - if ['asc', 'desc'].include? query[:sort_name] + if ["asc", "desc"].include? query[:sort_name] expr = expr.order_by("coalesce(NULLIF(supporters.name, ''), NULLIF(supporters.email, '')) #{query[:sort_name]}") end - if ['asc', 'desc'].include? query[:sort_type] + if ["asc", "desc"].include? query[:sort_type] expr = expr.order_by("payments.kind #{query[:sort_type]}") end - if ['asc', 'desc'].include? query[:sort_towards] + if ["asc", "desc"].include? query[:sort_towards] expr = expr.order_by("NULLIF(payments.towards, '') #{query[:sort_towards]}") end expr = expr.with(:nonprofits, get_nonprofit_query(npo_id), materialized: true) - expr = expr.with(:payments, get_nonprofit_payments_query(npo_id), materialized: false) - - return expr + expr.with(:payments, get_nonprofit_payments_query(npo_id), materialized: false) end # perform the search but only get the relevant payment_ids def self.select_to_filter_search(npo_id, query) - inner_donation_search = Qexpr.new.select('donations.*').from('donations') - if (query[:event_id].present?) - inner_donation_search = inner_donation_search.where('donations.event_id=$id', id: query[:event_id]) + inner_donation_search = Qexpr.new.select("donations.*").from("donations") + if query[:event_id].present? + inner_donation_search = inner_donation_search.where("donations.event_id=$id", id: query[:event_id]) end - if (query[:campaign_id].present?) + if query[:campaign_id].present? campaign_search = campaign_and_child_query_as_raw_string inner_donation_search = inner_donation_search.where("donations.campaign_id IN (#{campaign_search})", id: query[:campaign_id]) end # We are including deleted supporters on this query because deleted supporters may have made # payments. - expr = Qexpr.new.select('payments.id').from('payments') - .inner_join('supporters', "supporters.id=payments.supporter_id") - .inner_join('nonprofits', 'nonprofits.id=payments.nonprofit_id') - .left_outer_join(inner_donation_search.as('donations'), 'donations.id=payments.donation_id' ) - .where('payments.nonprofit_id=$id', id: npo_id.to_i) + expr = Qexpr.new.select("payments.id").from("payments") + .inner_join("supporters", "supporters.id=payments.supporter_id") + .inner_join("nonprofits", "nonprofits.id=payments.nonprofit_id") + .left_outer_join(inner_donation_search.as("donations"), "donations.id=payments.donation_id") + .where("payments.nonprofit_id=$id", id: npo_id.to_i) if query[:ids].present? if query[:ids].is_a? String - query[:ids] = query[:ids].split(',') + query[:ids] = query[:ids].split(",") end - if query[:ids].is_a?(Array) && query[:ids].all?{|i| i.to_i != 0} + if query[:ids].is_a?(Array) && query[:ids].all? { |i| i.to_i != 0 } expr = expr.where("payments.id IN ($ids)", ids: query[:ids]) end - end + end if query[:search].present? expr = SearchVector.query(query[:search], expr) end - unless (query[:campaign_id].present? || query[:event_id].present?) # if we need to add the reverse query, we can't add this here. - if ['asc', 'desc'].include? query[:sort_amount] + unless query[:campaign_id].present? || query[:event_id].present? # if we need to add the reverse query, we can't add this here. + if ["asc", "desc"].include? query[:sort_amount] expr = expr.order_by("payments.gross_amount #{query[:sort_amount]}") end - if ['asc', 'desc'].include? query[:sort_date] + if ["asc", "desc"].include? query[:sort_date] expr = expr.order_by("payments.date #{query[:sort_date]}") end - if ['asc', 'desc'].include? query[:sort_name] + if ["asc", "desc"].include? query[:sort_name] expr = expr.order_by("coalesce(NULLIF(supporters.name, ''), NULLIF(supporters.email, '')) #{query[:sort_name]}") end - if ['asc', 'desc'].include? query[:sort_type] + if ["asc", "desc"].include? query[:sort_type] expr = expr.order_by("payments.kind #{query[:sort_type]}") end - if ['asc', 'desc'].include? query[:sort_towards] + if ["asc", "desc"].include? query[:sort_towards] expr = expr.order_by("NULLIF(payments.towards, '') #{query[:sort_towards]}") end end if query[:after_date].present? - expr = expr.where('payments.date >= timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $date))', date: query[:after_date]) + expr = expr.where("payments.date >= timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $date))", date: query[:after_date]) end if query[:before_date].present? - expr = expr.where('payments.date <= timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $date))', date: query[:before_date]) + expr = expr.where("payments.date <= timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $date))", date: query[:before_date]) end if query[:amount_greater_than].present? - expr = expr.where('payments.gross_amount >= $amt', amt: query[:amount_greater_than].to_i * 100) + expr = expr.where("payments.gross_amount >= $amt", amt: query[:amount_greater_than].to_i * 100) end if query[:amount_less_than].present? - expr = expr.where('payments.gross_amount <= $amt', amt: query[:amount_less_than].to_i * 100) + expr = expr.where("payments.gross_amount <= $amt", amt: query[:amount_less_than].to_i * 100) end if query[:year].present? expr = expr - .where( - "to_char(timezone( - COALESCE(nonprofits.timezone, \'UTC\'), - timezone(\'UTC\', payments.date) + .where( + "to_char(timezone( + COALESCE(nonprofits.timezone, 'UTC'), + timezone('UTC', payments.date) ), 'YYYY')=$year", - year: (query[:year]).to_s - ) + year: query[:year].to_s + ) end if query[:designation].present? expr = expr.where("donations.designation @@ $s", s: "#{query[:designation]}") @@ -215,40 +207,40 @@ def self.select_to_filter_search(npo_id, query) expr = expr.where("donations.dedication @@ $s", s: "#{query[:dedication]}") end if query[:donation_type].present? - expr = expr.where('payments.kind IN ($kinds)', kinds: query[:donation_type].split(',')) + expr = expr.where("payments.kind IN ($kinds)", kinds: query[:donation_type].split(",")) end if query[:check_number].present? expr = expr - .join( - "offsite_payments", - "offsite_payments.payment_id = payments.id AND offsite_payments.check_number = $check_number", - check_number: query[:check_number] - ) + .join( + "offsite_payments", + "offsite_payments.payment_id = payments.id AND offsite_payments.check_number = $check_number", + check_number: query[:check_number] + ) end if query[:campaign_id].present? campaign_search = campaign_and_child_query_as_raw_string expr = expr - .left_outer_join("campaigns", "campaigns.id=donations.campaign_id" ) - .where("campaigns.id IN (#{campaign_search})", id: query[:campaign_id]) + .left_outer_join("campaigns", "campaigns.id=donations.campaign_id") + .where("campaigns.id IN (#{campaign_search})", id: query[:campaign_id]) end if query[:event_id].present? - tickets_subquery = Qexpr.new.select("payment_id", "MAX(event_id) AS event_id").from("tickets").where('tickets.event_id=$event_id', event_id: query[:event_id]).group_by("payment_id").as("tix") + tickets_subquery = Qexpr.new.select("payment_id", "MAX(event_id) AS event_id").from("tickets").where("tickets.event_id=$event_id", event_id: query[:event_id]).group_by("payment_id").as("tix") expr = expr - .left_outer_join(tickets_subquery, "tix.payment_id=payments.id") - .where("tix.event_id=$id OR donations.event_id=$id", id: query[:event_id]) + .left_outer_join(tickets_subquery, "tix.payment_id=payments.id") + .where("tix.event_id=$id OR donations.event_id=$id", id: query[:event_id]) end if query[:anonymous].present? - expr = if(query[:anonymous] == 'true') + expr = if query[:anonymous] == "true" expr.where( - '(supporters.anonymous OR donations.anonymous)' + "(supporters.anonymous OR donations.anonymous)" ) else expr.where( - '(NOT supporters.anonymous AND NOT donations.anonymous)' + "(NOT supporters.anonymous AND NOT donations.anonymous)" ) end end @@ -270,7 +262,7 @@ def self.select_to_filter_search(npo_id, query) if query.has_key? :online_payments_only if query[:online_payments_only] - expr = expr.join(:charges, "charges.payment_id = payments.id AND charges.status != $status", status: 'failed') + expr = expr.join(:charges, "charges.payment_id = payments.id AND charges.status != $status", status: "failed") end end @@ -278,7 +270,7 @@ def self.select_to_filter_search(npo_id, query) expr = expr.join(:tag_joins, "tag_joins.tag_master_id = $tag_master_id AND tag_joins.supporter_id = supporters.id", tag_master_id: query[:tag_master_id].to_i) end - #we have the first part of the search. We need to create the second in certain situations + # we have the first part of the search. We need to create the second in certain situations filtered_payment_id_search = expr.parse if query[:event_id].present? || query[:campaign_id].present? @@ -289,28 +281,27 @@ def self.select_to_filter_search(npo_id, query) end # we use this when we need to get the refund info - def self.create_reverse_select(npo_id, query) - inner_donation_search = Qexpr.new.select('donations.*').from('donations') - if (query[:event_id].present?) - inner_donation_search = inner_donation_search.where('donations.event_id=$id', id: query[:event_id]) + def self.create_reverse_select(npo_id, query) + inner_donation_search = Qexpr.new.select("donations.*").from("donations") + if query[:event_id].present? + inner_donation_search = inner_donation_search.where("donations.event_id=$id", id: query[:event_id]) end - if (query[:campaign_id].present?) + if query[:campaign_id].present? campaign_search = campaign_and_child_query_as_raw_string inner_donation_search = inner_donation_search.where("donations.campaign_id IN (#{campaign_search})", id: query[:campaign_id]) end - expr = Qexpr.new.select('payments.id').from('payments') - .inner_join('supporters', "supporters.id=payments.supporter_id") - .left_outer_join('refunds', 'payments.id=refunds.payment_id') - .left_outer_join('charges', 'refunds.charge_id=charges.id') - .left_outer_join('payments AS payments_orig', 'payments_orig.id=charges.payment_id') - .left_outer_join(inner_donation_search.as('donations'), 'donations.id=payments_orig.donation_id' ) - .where('payments.nonprofit_id=$id', id: npo_id.to_i) - + expr = Qexpr.new.select("payments.id").from("payments") + .inner_join("supporters", "supporters.id=payments.supporter_id") + .left_outer_join("refunds", "payments.id=refunds.payment_id") + .left_outer_join("charges", "refunds.charge_id=charges.id") + .left_outer_join("payments AS payments_orig", "payments_orig.id=charges.payment_id") + .left_outer_join(inner_donation_search.as("donations"), "donations.id=payments_orig.donation_id") + .where("payments.nonprofit_id=$id", id: npo_id.to_i) if query[:search].present? expr = SearchVector.query(query[:search], expr) end - + # This breaks so we need to scrap it # if ['asc', 'desc'].include? query[:sort_amount] # expr = expr.order_by("payments.gross_amount #{query[:sort_amount]}") @@ -328,16 +319,16 @@ def self.create_reverse_select(npo_id, query) # expr = expr.order_by("NULLIF(payments.towards, '') #{query[:sort_towards]}") # end if query[:after_date].present? - expr = expr.where('payments.date >= $date', date: query[:after_date]) + expr = expr.where("payments.date >= $date", date: query[:after_date]) end if query[:before_date].present? - expr = expr.where('payments.date <= $date', date: query[:before_date]) + expr = expr.where("payments.date <= $date", date: query[:before_date]) end if query[:amount_greater_than].present? - expr = expr.where('payments.gross_amount >= $amt', amt: query[:amount_greater_than].to_i * 100) + expr = expr.where("payments.gross_amount >= $amt", amt: query[:amount_greater_than].to_i * 100) end if query[:amount_less_than].present? - expr = expr.where('payments.gross_amount <= $amt', amt: query[:amount_less_than].to_i * 100) + expr = expr.where("payments.gross_amount <= $amt", amt: query[:amount_less_than].to_i * 100) end if query[:year].present? expr = expr.where("to_char(payments.date, 'YYYY')=$year", year: query[:year]) @@ -349,29 +340,29 @@ def self.create_reverse_select(npo_id, query) expr = expr.where("donations.dedication @@ $s", s: "#{query[:dedication]}") end if query[:donation_type].present? - expr = expr.where('payments.kind IN ($kinds)', kinds: query[:donation_type].split(',')) + expr = expr.where("payments.kind IN ($kinds)", kinds: query[:donation_type].split(",")) end if query[:check_number].present? expr = expr - .join( - "offsite_payments", - "offsite_payments.payment_id = payments.id AND offsite_payments.check_number = $check_number", - check_number: query[:check_number] - ) + .join( + "offsite_payments", + "offsite_payments.payment_id = payments.id AND offsite_payments.check_number = $check_number", + check_number: query[:check_number] + ) end if query[:campaign_id].present? campaign_search = campaign_and_child_query_as_raw_string expr = expr - .left_outer_join("campaigns", "campaigns.id=donations.campaign_id" ) - .where("campaigns.id IN (#{campaign_search})", id: query[:campaign_id]) + .left_outer_join("campaigns", "campaigns.id=donations.campaign_id") + .where("campaigns.id IN (#{campaign_search})", id: query[:campaign_id]) end if query[:event_id].present? - tickets_subquery = Qexpr.new.select("payment_id", "MAX(event_id) AS event_id").from("tickets").where('tickets.event_id=$event_id', event_id: query[:event_id]).group_by("payment_id").as("tix") + tickets_subquery = Qexpr.new.select("payment_id", "MAX(event_id) AS event_id").from("tickets").where("tickets.event_id=$event_id", event_id: query[:event_id]).group_by("payment_id").as("tix") expr = expr - .left_outer_join(tickets_subquery, "tix.payment_id=payments_orig.id") - .where("tix.event_id=$id OR donations.event_id=$id", id: query[:event_id]) + .left_outer_join(tickets_subquery, "tix.payment_id=payments_orig.id") + .where("tix.event_id=$id OR donations.event_id=$id", id: query[:event_id]) end @@ -384,18 +375,18 @@ def self.create_reverse_select(npo_id, query) def self.for_payout(npo_id, payout_id) tickets_subquery = Qx.select("payment_id", "MAX(event_id) AS event_id").from("tickets").group_by("payment_id").as("tickets") Qx.select( - "to_char(payouts.created_at, 'MM/DD/YYYY HH24:MIam') AS date", - "(payouts.gross_amount / 100.0)::money::text AS gross_total", - "(payouts.fee_total / 100.0)::money::text AS fee_total", - "(payouts.net_amount / 100.0)::money::text AS net_total", - "bank_accounts.name AS bank_name", - "payouts.status" - ) + "to_char(payouts.created_at, 'MM/DD/YYYY HH24:MIam') AS date", + "(payouts.gross_amount / 100.0)::money::text AS gross_total", + "(payouts.fee_total / 100.0)::money::text AS fee_total", + "(payouts.net_amount / 100.0)::money::text AS net_total", + "bank_accounts.name AS bank_name", + "payouts.status" + ) .from(:payouts) .join(:bank_accounts, "bank_accounts.nonprofit_id=payouts.nonprofit_id") .where("payouts.nonprofit_id=$id", id: npo_id) .and_where("payouts.id=$id", id: payout_id) - .execute(format: 'csv') + .execute(format: "csv") .concat([[]]) .concat( Qx.select([ @@ -405,7 +396,7 @@ def self.for_payout(npo_id, payout_id) "(payments.net_amount / 100.0)::money::text AS \"Net Amount\"", "payments.kind AS \"Type\"", "payments.id AS \"Payment ID\"" - ].concat(QuerySupporters.supporter_export_selections(:anonymous)) + ].concat(QuerySupporters.supporter_export_selections(:anonymous)) .concat([ "coalesce(donations.designation, 'None') AS \"Designation\"", "donations.dedication AS \"Honorarium/Memorium\"", @@ -415,9 +406,8 @@ def self.for_payout(npo_id, payout_id) "coalesce(nullif(campaign_gift_options.name, ''), 'None') AS \"Campaign Gift Level\"", "coalesce(events.name, 'None') AS \"Event\"", "coalesce(misc_payment_infos.fee_covered, 'f') AS \"Fee Covered?\"" - ]) - ) - .distinct_on('payments.date, payments.id') + ])) + .distinct_on("payments.date, payments.id") .from(:payments) .join(:payment_payouts, "payment_payouts.payment_id=payments.id") .add_join(:payouts, "payouts.id=payment_payouts.payout_id") @@ -432,29 +422,27 @@ def self.for_payout(npo_id, payout_id) .where("payouts.id=$id", id: payout_id) .and_where("payments.nonprofit_id=$id", id: npo_id) .order_by("payments.date DESC, payments.id") - .execute(format: 'csv') + .execute(format: "csv") ) end - def self.find_payments_where_too_far_from_charge_date(id=nil) + def self.find_payments_where_too_far_from_charge_date(id = nil) pay = Payment.includes(:donation).includes(:offsite_payment) - if (id) - pay = pay.where('id = ?', id) + if id + pay = pay.where("id = ?", id) end - pay = pay.where('date IS NOT NULL').order('id ASC') - pay.all.each{|p| - next if p.offsite_payment != nil - lowest_charge_for_payment = Charge.where('payment_id = ?', p.id).order('created_at ASC').limit(1).first + pay = pay.where.not(date: nil).order("id ASC") + pay.all.each { |p| + next if !p.offsite_payment.nil? + lowest_charge_for_payment = Charge.where("payment_id = ?", p.id).order("created_at ASC").limit(1).first - - if (lowest_charge_for_payment) + if lowest_charge_for_payment diff = p.date - lowest_charge_for_payment.created_at diff_too_big = diff > 10.minutes || diff < -10.minutes end - if (lowest_charge_for_payment && diff_too_big) + if lowest_charge_for_payment && diff_too_big yield(p.donation.id, p.donation.date, p.id, p.date, lowest_charge_for_payment.id, lowest_charge_for_payment.created_at, diff) end - } end @@ -471,7 +459,7 @@ def self.query_payout_info(npo_id, payout_id) "(payments.net_amount / 100.0)::money::text AS \"Net Amount\"", "payments.kind AS \"Type\"", "payments.id AS \"Payment ID\"" - ].concat(QuerySupporters.supporter_export_selections(:anonymous)) + ].concat(QuerySupporters.supporter_export_selections(:anonymous)) .concat([ "coalesce(donations.designation, 'None') AS \"Designation\"", "donations.dedication AS \"Honorarium/Memorium\"", @@ -480,25 +468,24 @@ def self.query_payout_info(npo_id, payout_id) "coalesce(nullif(campaigns.name, ''), 'None') AS \"Campaign\"", "coalesce(nullif(campaign_gift_options.name, ''), 'None') AS \"Campaign Gift Level\"", "coalesce(events.name, 'None') AS \"Event\"" - ]) - ) - .distinct_on('payments.date, payments.id') - .from(:payments) - .join(:payment_payouts, "payment_payouts.payment_id=payments.id") - .add_join(:payouts, "payouts.id=payment_payouts.payout_id") - .left_join(:supporters, "payments.supporter_id=supporters.id") - .add_left_join(:donations, "donations.id=payments.donation_id") - .add_left_join(:campaigns, "donations.campaign_id=campaigns.id") - .add_left_join(:campaign_gifts, "donations.id=campaign_gifts.donation_id") - .add_left_join(:campaign_gift_options, "campaign_gift_options.id=campaign_gifts.campaign_gift_option_id") - .add_left_join(tickets_subquery, "tickets.payment_id=payments.id") - .add_left_join(:events, "events.id=tickets.event_id OR (events.id = donations.event_id)") - .where("payouts.id=$id", id: payout_id) - .and_where("payments.nonprofit_id=$id", id: npo_id) - .order_by("payments.date DESC, payments.id") + ])) + .distinct_on("payments.date, payments.id") + .from(:payments) + .join(:payment_payouts, "payment_payouts.payment_id=payments.id") + .add_join(:payouts, "payouts.id=payment_payouts.payout_id") + .left_join(:supporters, "payments.supporter_id=supporters.id") + .add_left_join(:donations, "donations.id=payments.donation_id") + .add_left_join(:campaigns, "donations.campaign_id=campaigns.id") + .add_left_join(:campaign_gifts, "donations.id=campaign_gifts.donation_id") + .add_left_join(:campaign_gift_options, "campaign_gift_options.id=campaign_gifts.campaign_gift_option_id") + .add_left_join(tickets_subquery, "tickets.payment_id=payments.id") + .add_left_join(:events, "events.id=tickets.event_id OR (events.id = donations.event_id)") + .where("payouts.id=$id", id: payout_id) + .and_where("payments.nonprofit_id=$id", id: npo_id) + .order_by("payments.date DESC, payments.id") end def self.get_dedication_or_empty(*path) - "json_extract_path_text(coalesce(nullif(trim(both from donations.dedication), ''), '{}')::json, #{path.map{|i| "'#{i}'"}.join(',')})" + "json_extract_path_text(coalesce(nullif(trim(both from donations.dedication), ''), '{}')::json, #{path.map { |i| "'#{i}'" }.join(",")})" end end diff --git a/app/legacy_lib/query_profiles.rb b/app/legacy_lib/query_profiles.rb index c219f36b3..f82f6c35b 100644 --- a/app/legacy_lib/query_profiles.rb +++ b/app/legacy_lib/query_profiles.rb @@ -1,28 +1,27 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - module QueryProfiles - def self.for_admin(params) - expr = Qx.select( - 'profiles.name', - 'profiles.id', - 'profiles.created_at::date::text AS created_at', - 'users.confirmed_at AS is_confirmed', - 'users.email') + expr = Qx.select( + "profiles.name", + "profiles.id", + "profiles.created_at::date::text AS created_at", + "users.confirmed_at AS is_confirmed", + "users.email" + ) .from(:profiles) .add_left_join("users", "profiles.user_id=users.id") .order_by("profiles.created_at DESC") .paginate(params[:page].to_i, params[:page_length].to_i) - if params[:search].present? - expr = expr.where(%Q( + if params[:search].present? + expr = expr.where(%( profiles.name LIKE $search OR users.email LIKE $search OR users.name LIKE $search - ), search: '%' + params[:search].downcase + '%') - end + ), search: "%" + params[:search].downcase + "%") + end - return expr.execute + expr.execute end end diff --git a/app/legacy_lib/query_recurring_donations.rb b/app/legacy_lib/query_recurring_donations.rb index f34ee5e8a..1dafc4c37 100644 --- a/app/legacy_lib/query_recurring_donations.rb +++ b/app/legacy_lib/query_recurring_donations.rb @@ -1,94 +1,89 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryRecurringDonations - # Calculate a nonprofit's total recurring donations def self.monthly_total(np_id) Qx.select("coalesce(sum(amount), 0) AS sum") .from("recurring_donations") .where(nonprofit_id: np_id) - .and_where(is_external_active_clause('recurring_donations')) - .execute.first['sum'] + .and_where(is_external_active_clause("recurring_donations")) + .execute.first["sum"] end - # Fetch a single recurring donation for its edit page def self.fetch_for_edit(id) recurring_donation = Psql.execute( - Qexpr.new.select( - "recurring_donations.*", - "nonprofits.id AS nonprofit_id", - "nonprofits.name AS nonprofit_name", - "cards.name AS card_name" - ).from('recurring_donations') - .left_outer_join('donations', 'donations.id=recurring_donations.donation_id') - .left_outer_join('cards', 'donations.card_id=cards.id') - .left_outer_join('nonprofits', 'nonprofits.id=recurring_donations.nonprofit_id') - .where('recurring_donations.id=$id', id: id) - ).first - - return recurring_donation if !recurring_donation || !recurring_donation['id'] + Qexpr.new.select( + "recurring_donations.*", + "nonprofits.id AS nonprofit_id", + "nonprofits.name AS nonprofit_name", + "cards.name AS card_name" + ).from("recurring_donations") + .left_outer_join("donations", "donations.id=recurring_donations.donation_id") + .left_outer_join("cards", "donations.card_id=cards.id") + .left_outer_join("nonprofits", "nonprofits.id=recurring_donations.nonprofit_id") + .where("recurring_donations.id=$id", id: id) + ).first + + return recurring_donation if !recurring_donation || !recurring_donation["id"] supporter = Psql.execute( - Qexpr.new.select('*') - .from('supporters') - .where('id=$id', id: recurring_donation['supporter_id']) + Qexpr.new.select("*") + .from("supporters") + .where("id=$id", id: recurring_donation["supporter_id"]) ).first - nonprofit = Nonprofit.find(recurring_donation['nonprofit_id']) + nonprofit = Nonprofit.find(recurring_donation["nonprofit_id"]) - return { - 'recurring_donation' => recurring_donation, - 'supporter' => supporter, - 'nonprofit' => nonprofit + { + "recurring_donation" => recurring_donation, + "supporter" => supporter, + "nonprofit" => nonprofit } end - # Construct a full query for the dashboard/export listings def self.full_search_expr(np_id, query) include_last_failed_charge = !!query[:include_last_failed_charge] expr = Qexpr.new - .from('recurring_donations') - .left_outer_join('supporters', 'supporters.id=recurring_donations.supporter_id') - .join('donations', 'donations.id=recurring_donations.donation_id') - .left_outer_join('charges paid_charges', 'paid_charges.donation_id=donations.id') - .left_outer_join('misc_recurring_donation_infos', - 'misc_recurring_donation_infos.recurring_donation_id = recurring_donations.id') - .where('recurring_donations.nonprofit_id=$id', id: np_id.to_i) + .from("recurring_donations") + .left_outer_join("supporters", "supporters.id=recurring_donations.supporter_id") + .join("donations", "donations.id=recurring_donations.donation_id") + .left_outer_join("charges paid_charges", "paid_charges.donation_id=donations.id") + .left_outer_join("misc_recurring_donation_infos", + "misc_recurring_donation_infos.recurring_donation_id = recurring_donations.id") + .where("recurring_donations.nonprofit_id=$id", id: np_id.to_i) if include_last_failed_charge - expr = expr.left_outer_join("(SELECT created_at, donation_id FROM charges WHERE charges.status = 'failed') AS failed_charges", 'failed_charges.donation_id = donations.id') + expr = expr.left_outer_join("(SELECT created_at, donation_id FROM charges WHERE charges.status = 'failed') AS failed_charges", "failed_charges.donation_id = donations.id") end failed_or_active_clauses = [] if query.key?(:active_and_not_failed) - clause = query[:active_and_not_failed] ? is_external_active_clause('recurring_donations') : is_external_cancelled_clause('recurring_donations') + clause = query[:active_and_not_failed] ? is_external_active_clause("recurring_donations") : is_external_cancelled_clause("recurring_donations") failed_or_active_clauses.push("(#{clause})") end if query.key?(:active) - clause = query[:active] ? [is_active_clause('recurring_donations'), is_not_fulfilled_clause('recurring_donations')].join(" AND ") : [is_cancelled_clause('recurring_donations'), is_not_fulfilled_clause('recurring_donations')].join(" AND ") + clause = query[:active] ? [is_active_clause("recurring_donations"), is_not_fulfilled_clause("recurring_donations")].join(" AND ") : [is_cancelled_clause("recurring_donations"), is_not_fulfilled_clause("recurring_donations")].join(" AND ") failed_or_active_clauses.push("(#{clause})") end if query.key?(:failed) - clause = query[:failed] ? [is_failed_clause('recurring_donations'), is_active_clause('recurring_donations')].join(" AND ") : is_not_failed_clause('recurring_donations') + clause = query[:failed] ? [is_failed_clause("recurring_donations"), is_active_clause("recurring_donations")].join(" AND ") : is_not_failed_clause("recurring_donations") failed_or_active_clauses.push("(#{clause})") end if query.key?(:fulfilled) - clause = query[:fulfilled] ? [is_fulfilled_clause('recurring_donations'), is_active_clause('recurring_donations')].join(" AND ") : is_not_fulfilled_clause('recurring_donations') + clause = query[:fulfilled] ? [is_fulfilled_clause("recurring_donations"), is_active_clause("recurring_donations")].join(" AND ") : is_not_fulfilled_clause("recurring_donations") failed_or_active_clauses.push("(#{clause})") end - if (failed_or_active_clauses.any?) - expr = expr.where("#{failed_or_active_clauses.join(' OR ')}") + if failed_or_active_clauses.any? + expr = expr.where("#{failed_or_active_clauses.join(" OR ")}") end - - if query.key?(:end_date_gt_or_equal) expr = expr.where("recurring_donations.end_date IS NULL OR recurring_donations.end_date >= $date", date: query[:end_date_gt_or_equal]) end @@ -97,109 +92,107 @@ def self.full_search_expr(np_id, query) expr = expr.where( 'failed_charges.created_at >= $from_date AND failed_charges.created_at < $before_date', - { from_date: query[:from_date], before_date: query[:before_date] } + {from_date: query[:from_date], before_date: query[:before_date]} ) end - expr = expr.where("paid_charges.id IS NULL OR paid_charges.status != 'failed'") - .group_by('recurring_donations.id') - .order_by('recurring_donations.created_at') + expr = expr.where("paid_charges.id IS NULL OR paid_charges.status != 'failed'") + .group_by("recurring_donations.id") + .order_by("recurring_donations.created_at") if query[:cancelled_at_gt_or_equal].present? - expr = expr.where('recurring_donations.cancelled_at >= $date', date: query[:cancelled_at_gt_or_equal]) + expr = expr.where("recurring_donations.cancelled_at >= $date", date: query[:cancelled_at_gt_or_equal]) end if query[:cancelled_at_lt].present? - expr = expr.where('recurring_donations.cancelled_at < $date', date: query[:cancelled_at_lt]) + expr = expr.where("recurring_donations.cancelled_at < $date", date: query[:cancelled_at_lt]) end if query[:search].present? - matcher = "%#{query[:search].downcase.split(' ').join('%')}%" - expr = expr.where(%Q(( + matcher = "%#{query[:search].downcase.split(" ").join("%")}%" + expr = expr.where(%(( lower(supporters.name) LIKE $name OR lower(supporters.email) LIKE $email OR recurring_donations.amount=$amount OR recurring_donations.id=$id )), {name: matcher, email: matcher, amount: query[:search].to_i, id: query[:search].to_i}) end - return expr + expr end - # Fetch the full table of results for the dashboard - def self.full_list(np_id, query={}) + def self.full_list(np_id, query = {}) limit = 30 offset = Qexpr.page_offset(limit, query[:page]) expr = full_search_expr(np_id, query).select( - 'recurring_donations.start_date', - 'recurring_donations.interval', - 'recurring_donations.time_unit', - 'recurring_donations.n_failures', - 'recurring_donations.amount', - 'recurring_donations.id AS id', - 'MAX(supporters.email) AS email', - 'MAX(supporters.name) AS name', - 'MAX(supporters.id) AS supporter_id', - 'SUM(paid_charges.amount) AS total_given') + "recurring_donations.start_date", + "recurring_donations.interval", + "recurring_donations.time_unit", + "recurring_donations.n_failures", + "recurring_donations.amount", + "recurring_donations.id AS id", + "MAX(supporters.email) AS email", + "MAX(supporters.name) AS name", + "MAX(supporters.id) AS supporter_id", + "SUM(paid_charges.amount) AS total_given" + ) .limit(limit).offset(offset) data = Psql.execute(expr) total_count = Psql.execute( - Qexpr.new.select('COUNT(rds)') - .from(full_search_expr(np_id, query).remove(:order_by).select('recurring_donations.id'), 'rds') - ).first['count'] + Qexpr.new.select("COUNT(rds)") + .from(full_search_expr(np_id, query).remove(:order_by).select("recurring_donations.id"), "rds") + ).first["count"] total_amount = monthly_total(np_id) - return { + { data: data, total_amount: total_amount, total_count: total_count, - remaining: Qexpr.remaining_count(total_count, limit, query[:page]), + remaining: Qexpr.remaining_count(total_count, limit, query[:page]) } end - def self.for_export_enumerable(npo_id, query, chunk_limit=15000) - ParamValidation.new({npo_id: npo_id, query:query}, {npo_id: {required: true, is_int: true}, - query: {required:true, is_hash: true}}) + def self.for_export_enumerable(npo_id, query, chunk_limit = 15000) + ParamValidation.new({npo_id: npo_id, query: query}, {npo_id: {required: true, is_int: true}, + query: {required: true, is_hash: true}}) - return QexprQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| + QexprQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| get_chunk_of_export(npo_id, query, offset, limit, skip_header) end - end - def self.get_chunk_of_export(npo_id, query, offset=nil, limit=nil, skip_header=false ) - root_url = query[:root_url] || 'https://us.commitchange.com/' + def self.get_chunk_of_export(npo_id, query, offset = nil, limit = nil, skip_header = false) + root_url = query[:root_url] || "https://us.commitchange.com/" include_stripe_customer_id = query[:include_stripe_customer_id] include_last_failed_charge = !!query[:include_last_failed_charge] - select_list = ['recurring_donations.created_at', - '(recurring_donations.amount / 100.0)::money::text AS amount', - "concat('Every ', recurring_donations.interval, ' ', recurring_donations.time_unit, '(s)') AS interval", - '(SUM(paid_charges.amount) / 100.0)::money::text AS total_contributed', - 'MAX(campaigns.name) AS campaign_name', - 'MAX(supporters.name) AS supporter_name', - 'MAX(supporters.email) AS supporter_email', - 'MAX(supporters.phone) AS phone', - 'MAX(supporters.address) AS address', - 'MAX(supporters.city) AS city', - 'MAX(supporters.state_code) AS state', - 'MAX(supporters.zip_code) AS zip_code', - 'MAX(cards.name) AS card_name', - 'recurring_donations.id AS "Recurring Donation ID"', - 'MAX(donations.id) AS "Donation ID"', - 'MAX(donations.designation) AS "Designation"', - 'BOOL_OR(misc_recurring_donation_infos.fee_covered) AS "Fee Covered by Supporter"', - "CASE WHEN #{is_cancelled_clause('recurring_donations')} + select_list = ["recurring_donations.created_at", + "(recurring_donations.amount / 100.0)::money::text AS amount", + "concat('Every ', recurring_donations.interval, ' ', recurring_donations.time_unit, '(s)') AS interval", + "(SUM(paid_charges.amount) / 100.0)::money::text AS total_contributed", + "MAX(campaigns.name) AS campaign_name", + "MAX(supporters.name) AS supporter_name", + "MAX(supporters.email) AS supporter_email", + "MAX(supporters.phone) AS phone", + "MAX(supporters.address) AS address", + "MAX(supporters.city) AS city", + "MAX(supporters.state_code) AS state", + "MAX(supporters.zip_code) AS zip_code", + "MAX(cards.name) AS card_name", + 'recurring_donations.id AS "Recurring Donation ID"', + 'MAX(donations.id) AS "Donation ID"', + 'MAX(donations.designation) AS "Designation"', + 'BOOL_OR(misc_recurring_donation_infos.fee_covered) AS "Fee Covered by Supporter"', + "CASE WHEN #{is_cancelled_clause("recurring_donations")} THEN 'cancelled' - WHEN #{is_failed_clause('recurring_donations')} + WHEN #{is_failed_clause("recurring_donations")} THEN 'failed' - WHEN #{is_fulfilled_clause('recurring_donations')} + WHEN #{is_fulfilled_clause("recurring_donations")} THEN 'fulfilled' ELSE 'active' END AS status", - 'recurring_donations.cancelled_at AS "Cancelled At"', - "CASE WHEN (#{is_active_clause('recurring_donations')} OR #{is_failed_clause('recurring_donations')}) AND #{is_not_fulfilled_clause('recurring_donations')} THEN concat('#{root_url}recurring_donations/', recurring_donations.id, '/edit?t=', recurring_donations.edit_token) ELSE '' END AS \"Donation Management Url\"", - 'MAX(recurring_donations.paydate) AS "Paydate"', - 'MAX(paid_charges.created_at) AS "Last Charge Succeeded"' - ] + 'recurring_donations.cancelled_at AS "Cancelled At"', + "CASE WHEN (#{is_active_clause("recurring_donations")} OR #{is_failed_clause("recurring_donations")}) AND #{is_not_fulfilled_clause("recurring_donations")} THEN concat('#{root_url}recurring_donations/', recurring_donations.id, '/edit?t=', recurring_donations.edit_token) ELSE '' END AS \"Donation Management Url\"", + 'MAX(recurring_donations.paydate) AS "Paydate"', + 'MAX(paid_charges.created_at) AS "Last Charge Succeeded"'] if include_last_failed_charge select_list.push('MAX(failed_charges.created_at) AS "Last Failed Charge"') @@ -208,23 +201,23 @@ def self.get_chunk_of_export(npo_id, query, offset=nil, limit=nil, skip_header=f if include_stripe_customer_id select_list.push 'MAX(cards.stripe_customer_id) AS "Stripe Customer ID"' end - return QexprQueryChunker.get_chunk_of_query(offset, limit, skip_header) { - full_search_expr(npo_id, query).select(select_list) - .left_outer_join('campaigns' , 'campaigns.id=donations.campaign_id') - .left_outer_join('cards', 'cards.id=donations.card_id') - # .left_outer_join('misc_recurring_donation_infos', 'recurring_donations.id = misc_recurring_donation_infos.recurring_donation_id') + QexprQueryChunker.get_chunk_of_query(offset, limit, skip_header) { + full_search_expr(npo_id, query).select(select_list) + .left_outer_join("campaigns", "campaigns.id=donations.campaign_id") + .left_outer_join("cards", "cards.id=donations.card_id") + # .left_outer_join('misc_recurring_donation_infos', 'recurring_donations.id = misc_recurring_donation_infos.recurring_donation_id') } end - def self.recurring_donations_without_cards RecurringDonation.active.includes(:card).includes(:charges).includes(:donation).includes(:nonprofit).includes(:supporter).where("cards.id IS NULL").order("recurring_donations.created_at DESC") end # @param [Supporter] supporter def self.find_recurring_donation_with_a_card(supporter) - supporter.recurring_donations.select{|rd| - rd.donation != nil && rd.donation.card != nil}.first() + supporter.recurring_donations.select { |rd| + !rd.donation.nil? && !rd.donation.card.nil? + }.first end # Check if a single recdon is due -- used in PayRecurringDonation.with_stripe @@ -235,7 +228,6 @@ def self.is_due?(rd_id) ).any? end - # Sql partial expression # Select all due recurring donations # Can use this for all donations in the db, or extend the query for only those with a nonprofit_id, supporter_id, etc (see is_due?) @@ -243,23 +235,23 @@ def self.is_due?(rd_id) def self._all_that_are_due now = Time.current Qexpr.new.select("recurring_donations.id") - .from(:recurring_donations) - .where("recurring_donations.active='t'") - .where("coalesce(recurring_donations.n_failures, 0) < 3") - .where("recurring_donations.start_date IS NULL OR recurring_donations.start_date <= $now", now: now) - .where("recurring_donations.end_date IS NULL OR recurring_donations.end_date > $now", now: now) - .where("(recurring_donation_holds.id IS NULL OR recurring_donation_holds.end_date IS NULL OR (recurring_donation_holds.end_date IS NOT NULL AND recurring_donation_holds.end_date <= $now))", now: now) - .join('donations','recurring_donations.donation_id=donations.id and (donations.payment_provider IS NULL OR donations.payment_provider!=\'sepa\')') - .left_outer_join( # Join the most recent paid charge - Qexpr.new.select(:donation_id, "MAX(created_at) AS created_at") - .from(:charges) - .where("status != 'failed'") - .group_by("donation_id") - .as("last_charge"), - "last_charge.donation_id=recurring_donations.donation_id" - ) - .left_outer_join('recurring_donation_holds', 'recurring_donation_holds.recurring_donation_id = recurring_donations.id') - .where(%Q( + .from(:recurring_donations) + .where("recurring_donations.active='t'") + .where("coalesce(recurring_donations.n_failures, 0) < 3") + .where("recurring_donations.start_date IS NULL OR recurring_donations.start_date <= $now", now: now) + .where("recurring_donations.end_date IS NULL OR recurring_donations.end_date > $now", now: now) + .where("(recurring_donation_holds.id IS NULL OR recurring_donation_holds.end_date IS NULL OR (recurring_donation_holds.end_date IS NOT NULL AND recurring_donation_holds.end_date <= $now))", now: now) + .join("donations", "recurring_donations.donation_id=donations.id and (donations.payment_provider IS NULL OR donations.payment_provider!='sepa')") + .left_outer_join( # Join the most recent paid charge + Qexpr.new.select(:donation_id, "MAX(created_at) AS created_at") + .from(:charges) + .where("status != 'failed'") + .group_by("donation_id") + .as("last_charge"), + "last_charge.donation_id=recurring_donations.donation_id" + ) + .left_outer_join("recurring_donation_holds", "recurring_donation_holds.recurring_donation_id = recurring_donations.id") + .where(%( last_charge.donation_id IS NULL OR ( (recurring_donations.time_unit != 'month' OR recurring_donations.interval != 1) @@ -287,11 +279,12 @@ def self._all_that_are_due beginning_of_last_month: (now - 1.month).beginning_of_month, today: now.day }) - .order_by('recurring_donations.created_at') + .order_by("recurring_donations.created_at") end + # Some general statistics for a nonprofit def self.overall_stats(np_id) - return Psql.execute( + Psql.execute( Qexpr.new.from(:recurring_donations) .select( "money(avg(recurring_donations.amount) / 100.0) AS average", @@ -304,10 +297,10 @@ def self.overall_stats(np_id) "money(coalesce(sum(rds_cancelled.amount), 0) / 100.0) AS cancelled_sum", "coalesce(count(rds_cancelled), 0) AS cancelled_count" ) - .left_outer_join('recurring_donations rds_active', "rds_active.id=recurring_donations.id AND #{is_external_active_clause('rds_active')}") - .left_outer_join('recurring_donations rds_inactive', "rds_inactive.id=recurring_donations.id AND #{is_external_cancelled_clause('rds_inactive')}") - .left_outer_join('recurring_donations rds_failed', "rds_failed.id=recurring_donations.id AND #{is_failed_clause('rds_failed')}") - .left_outer_join('recurring_donations rds_cancelled', "rds_cancelled.id=recurring_donations.id AND #{is_cancelled_clause('rds_cancelled')}") + .left_outer_join("recurring_donations rds_active", "rds_active.id=recurring_donations.id AND #{is_external_active_clause("rds_active")}") + .left_outer_join("recurring_donations rds_inactive", "rds_inactive.id=recurring_donations.id AND #{is_external_cancelled_clause("rds_inactive")}") + .left_outer_join("recurring_donations rds_failed", "rds_failed.id=recurring_donations.id AND #{is_failed_clause("rds_failed")}") + .left_outer_join("recurring_donations rds_cancelled", "rds_cancelled.id=recurring_donations.id AND #{is_cancelled_clause("rds_cancelled")}") .where("recurring_donations.nonprofit_id=$id", id: np_id) ).first end @@ -334,7 +327,6 @@ def self.is_not_fulfilled_clause(field_for_rd) "NOT(#{is_fulfilled_clause(field_for_rd)})" end - def self.is_cancelled_clause(field_for_rd) "NOT (#{is_active_clause(field_for_rd)})" end @@ -349,21 +341,23 @@ def self.is_failed_clause(field_for_rd) def self.last_charge Qexpr.new.select(:donation_id, "MAX(created_at) AS created_at") - .from(:charges) - .where("status != 'failed'") - .group_by("donation_id") - .as("last_charge") + .from(:charges) + .where("status != 'failed'") + .group_by("donation_id") + .as("last_charge") end def self.export_for_transfer(nonprofit_id) - items = RecurringDonation.where("nonprofit_id = ?", nonprofit_id).active.includes('supporter').includes('card').to_a - output = items.map{|i| {supporter: i.supporter.id, - supporter_name: i.supporter.name, - supporter_email: i.supporter.email, - amount: i.amount, - paydate: i.paydate, - card: i.card.stripe_card_id}} - return output.to_a + items = RecurringDonation.where("nonprofit_id = ?", nonprofit_id).active.includes("supporter").includes("card").to_a + output = items.map { |i| + {supporter: i.supporter.id, + supporter_name: i.supporter.name, + supporter_email: i.supporter.email, + amount: i.amount, + paydate: i.paydate, + card: i.card.stripe_card_id} + } + output.to_a end def self.get_active_recurring_for_an_org(nonprofit) @@ -371,14 +365,10 @@ def self.get_active_recurring_for_an_org(nonprofit) result = generate_output_by_supporter_email_groups(supporter_groups_by_email) - Format::Csv.from_data(result, titleize_header: false) - - - end - def self.get_new_recurring_for_an_org_during_a_period(nonprofit, start_date_for_search=nil , end_date_for_search=nil) + def self.get_new_recurring_for_an_org_during_a_period(nonprofit, start_date_for_search = nil, end_date_for_search = nil) if start_date_for_search.nil? || end_date_for_search.nil? start_date_for_search = Time.current.beginning_of_month - 1.month end_date_for_search = Time.current.beginning_of_month @@ -392,14 +382,14 @@ def self.get_new_recurring_for_an_org_during_a_period(nonprofit, start_date_for_ def self.generate_output_by_supporter_email_groups(supporter_groups_by_email) supporter_groups_by_email.map do |supporter_group| - all_supporters = supporter_group.supporters.map{|id| Supporter.includes(:recurring_donations, :tag_joins => :tag_master).find(id)} - tags = all_supporters.map{|s| s.tag_joins.joins(:tag_master).where("NOT tag_masters.deleted").references(:tag_masters).pluck("tag_masters.name")}.flatten - recurrings = all_supporters.map{|supporter| supporter.recurring_donations.active.unfailed.order("start_date DESC")}.flatten.sort_by{|i| i.start_date}.reverse + all_supporters = supporter_group.supporters.map { |id| Supporter.includes(:recurring_donations, tag_joins: :tag_master).find(id) } + tags = all_supporters.map { |s| s.tag_joins.joins(:tag_master).where("NOT tag_masters.deleted").references(:tag_masters).pluck("tag_masters.name") }.flatten + recurrings = all_supporters.map { |supporter| supporter.recurring_donations.active.unfailed.order("start_date DESC") }.flatten.sort_by { |i| i.start_date }.reverse { email: supporter_group.email, - tags: tags.join(','), - active_recurring_donations: recurrings.map{|recurring| recurring.amount.to_s + ',' + recurring.start_date.to_datetime.utc.to_i.to_s}.join(';') + tags: tags.join(","), + active_recurring_donations: recurrings.map { |recurring| recurring.amount.to_s + "," + recurring.start_date.to_datetime.utc.to_i.to_s }.join(";") } end end diff --git a/app/legacy_lib/query_roles.rb b/app/legacy_lib/query_roles.rb index 01db62516..540c76d30 100644 --- a/app/legacy_lib/query_roles.rb +++ b/app/legacy_lib/query_roles.rb @@ -1,27 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryRoles + def self.user_has_role?(user_id, role_names, host_id = nil) + expr = Qx.select("COUNT(roles)").from(:roles) + .where("name IN ($names)", names: Array(role_names)) + .and_where(user_id: user_id) + expr = expr.and_where(host_id: host_id) if host_id + expr.execute.first["count"] > 0 + end - def self.user_has_role?(user_id, role_names, host_id=nil) - expr = Qx.select("COUNT(roles)").from(:roles) - .where("name IN ($names)", names: Array(role_names)) - .and_where(user_id: user_id) - expr = expr.and_where(host_id: host_id) if host_id - return expr.execute.first['count'] > 0 - end + # Get host tables -- host can be nonprofit, campaign, event + def self.host_ids(user_id, role_names) + Qx.select("host_id").from(:roles) + .where(user_id: user_id) + .and_where("roles.name IN ($names)", names: role_names) + .execute.map { |h| h["host_id"] } + end - # Get host tables -- host can be nonprofit, campaign, event - def self.host_ids(user_id, role_names) - Qx.select("host_id").from(:roles) - .where(user_id: user_id) - .and_where("roles.name IN ($names)", names: role_names) - .execute.map{|h| h['host_id']} - end + def self.is_nonprofit_user?(user_id, np_id) + user_has_role?(user_id, [:nonprofit_admin, :nonprofit_associate], np_id) + end - def self.is_nonprofit_user?(user_id, np_id) - user_has_role?(user_id, [:nonprofit_admin, :nonprofit_associate], np_id) - end - - def self.is_authorized_for_nonprofit?(user_id, np_id) - user_has_role?(user_id, [:super_admin]) || is_nonprofit_user?(user_id, np_id) - end -end \ No newline at end of file + def self.is_authorized_for_nonprofit?(user_id, np_id) + user_has_role?(user_id, [:super_admin]) || is_nonprofit_user?(user_id, np_id) + end +end diff --git a/app/legacy_lib/query_source_token.rb b/app/legacy_lib/query_source_token.rb index 25a7abb62..b8dfe9835 100644 --- a/app/legacy_lib/query_source_token.rb +++ b/app/legacy_lib/query_source_token.rb @@ -12,9 +12,9 @@ module QuerySourceToken # or we're past the expiration date def self.get_and_increment_source_token(token, user = nil) ParamValidation.new({token: token}, { - token: {required: true, format: UUID::Regex} + token: {required: true, format: UUID::Regex} }) - source_token = SourceToken.where('token = ?', token).first + source_token = SourceToken.where("token = ?", token).first if source_token source_token.with_lock { unless source_token_unexpired?(source_token) @@ -34,13 +34,12 @@ def self.get_and_increment_source_token(token, user = nil) source_token.save! } else - raise ParamValidation::ValidationError.new "#{token} doesn't represent a valid source", {:key => :token} + raise ParamValidation::ValidationError.new "#{token} doesn't represent a valid source", {key: :token} end source_token end - def self.source_token_unexpired?(source_token) if source_token.max_uses <= source_token.total_uses return false @@ -57,4 +56,4 @@ def self.validate_source_token_type(source_token) raise ParamValidation::ValidationError.new("The item for token #{data[:token]} is not a Card", key: :token) end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/query_supporters.rb b/app/legacy_lib/query_supporters.rb index 916836aa8..1553f7d1c 100644 --- a/app/legacy_lib/query_supporters.rb +++ b/app/legacy_lib/query_supporters.rb @@ -1,83 +1,81 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qexpr' -require 'psql' -require 'email' -require 'format/currency' -require 'format/csv' +require "qexpr" +require "psql" +require "email" +require "format/currency" +require "format/csv" module QuerySupporters - # Query supporters and their donations and gift levels for a campaign def self.campaign_list_expr(np_id, campaign_id, query) - expr = Qexpr.new.from('supporters') - .left_outer_join('donations', 'donations.supporter_id=supporters.id') - .left_outer_join('campaign_gifts', 'donations.id=campaign_gifts.donation_id') - .left_outer_join('campaign_gift_options', 'campaign_gifts.campaign_gift_option_id=campaign_gift_options.id') - .join_lateral(:payments, Qx - .select('payments.id, payments.gross_amount').from(:payments) - .where('payments.donation_id = donations.id') - .order_by('payments.created_at ASC') + expr = Qexpr.new.from("supporters") + .left_outer_join("donations", "donations.supporter_id=supporters.id") + .left_outer_join("campaign_gifts", "donations.id=campaign_gifts.donation_id") + .left_outer_join("campaign_gift_options", "campaign_gifts.campaign_gift_option_id=campaign_gift_options.id") + .join_lateral(:payments, Qx + .select("payments.id, payments.gross_amount").from(:payments) + .where("payments.donation_id = donations.id") + .order_by("payments.created_at ASC") .limit(1).parse, true) - .join(Qx.select('id, profile_id').from('campaigns') + .join(Qx.select("id, profile_id").from("campaigns") .where("id IN (#{QueryCampaigns .get_campaign_and_children(campaign_id) - .parse})").as('campaigns').parse, - 'donations.campaign_id=campaigns.id') - .join(Qx.select('users.id, profiles.id AS profiles_id, users.email') - .from('users') - .add_join('profiles', 'profiles.user_id = users.id') + .parse})").as("campaigns").parse, + "donations.campaign_id=campaigns.id") + .join(Qx.select("users.id, profiles.id AS profiles_id, users.email") + .from("users") + .add_join("profiles", "profiles.user_id = users.id") .as("users").parse, "users.profiles_id=campaigns.profile_id") - .where("supporters.nonprofit_id=$id", id: np_id) - .group_by('supporters.id') - .order_by('MAX(donations.date) DESC') + .where("supporters.nonprofit_id=$id", id: np_id) + .group_by("supporters.id") + .order_by("MAX(donations.date) DESC") - if query[:search].present? - expr = expr.where(%Q( + if query[:search].present? + expr = expr.where(%( supporters.name ILIKE $search OR supporters.email ILIKE $search OR campaign_gift_options.name ILIKE $search - ), search: '%' + query[:search] + '%') + ), search: "%" + query[:search] + "%") end - return expr + expr end - - # Used in the campaign donor listing - def self.campaign_list(np_id, campaign_id, query) + # Used in the campaign donor listing + def self.campaign_list(np_id, campaign_id, query) limit = 50 offset = Qexpr.page_offset(limit, query[:page]) data = Psql.execute( campaign_list_expr(np_id, campaign_id, query).select( - 'supporters.id', - 'supporters.name', - 'supporters.email', - 'SUM(payments.gross_amount) AS total_raised', - 'ARRAY_AGG(DISTINCT campaign_gift_options.name) AS campaign_gift_names', - 'DATE(MAX(donations.created_at)) AS latest_gift', - 'ARRAY_AGG(DISTINCT users.email) AS campaign_creator_emails' + "supporters.id", + "supporters.name", + "supporters.email", + "SUM(payments.gross_amount) AS total_raised", + "ARRAY_AGG(DISTINCT campaign_gift_options.name) AS campaign_gift_names", + "DATE(MAX(donations.created_at)) AS latest_gift", + "ARRAY_AGG(DISTINCT users.email) AS campaign_creator_emails" ).limit(limit).offset(offset) ) total_count = Psql.execute( Qexpr.new.select("COUNT(s)") - .from(campaign_list_expr(np_id, campaign_id, query).remove(:order_by).select('supporters.id').as('s').parse) - ).first['count'] + .from(campaign_list_expr(np_id, campaign_id, query).remove(:order_by).select("supporters.id").as("s").parse) + ).first["count"] - return { - data: data, - total_count: total_count, - remaining: Qexpr.remaining_count(total_count, limit, query[:page]) + { + data: data, + total_count: total_count, + remaining: Qexpr.remaining_count(total_count, limit, query[:page]) } - end + end def self.full_search_metrics(np_id, query) total_count = full_filter_expr(np_id, query) .select("COUNT(supporters)") .remove_clause(:order_by) - .execute.first['count'] + .execute.first["count"] - return { + { total_count: total_count, remaining_count: Qexpr.remaining_count(total_count, 30, query[:page]) } @@ -86,11 +84,11 @@ def self.full_search_metrics(np_id, query) # Full supporter search mainly for /nonprofits/id/supporters dashboard def self.full_search(np_id, query) select = [ - 'supporters.name', - 'supporters.email', - 'supporters.is_unsubscribed_from_emails', - 'supporters.id AS id', - 'tags.names AS tags', + "supporters.name", + "supporters.email", + "supporters.is_unsubscribed_from_emails", + "supporters.id AS id", + "tags.names AS tags", "to_char( timezone( COALESCE(nonprofits.timezone, 'UTC'), @@ -98,10 +96,10 @@ def self.full_search(np_id, query) ), 'MM/DD/YY' ) AS last_contribution", - 'payments.sum AS total_raised' + "payments.sum AS total_raised" ] if query[:select] - select += query[:select].split(',') + select += query[:select].split(",") end supps = full_filter_expr(np_id, query) @@ -109,31 +107,29 @@ def self.full_search(np_id, query) .paginate(query[:page].to_i, 30) .execute - return { data: supps } + {data: supps} end - - def self._full_search(np_id, query) select = [ - 'supporters.name', - 'supporters.email', - 'supporters.is_unsubscribed_from_emails', - 'supporters.id AS id', - 'tags.names AS tags', - "to_char(payments.max_date, 'MM/DD/YY') AS last_contribution", - 'payments.sum AS total_raised' + "supporters.name", + "supporters.email", + "supporters.is_unsubscribed_from_emails", + "supporters.id AS id", + "tags.names AS tags", + "to_char(payments.max_date, 'MM/DD/YY') AS last_contribution", + "payments.sum AS total_raised" ] if query[:select] - select += query[:select].split(',') + select += query[:select].split(",") end supps = full_filter_expr(np_id, query) - .select(*select) - .paginate(query[:page].to_i, query[:page_length].to_i) - .execute + .select(*select) + .paginate(query[:page].to_i, query[:page_length].to_i) + .execute - return { data: supps } + {data: supps} end # # Given a list of supporters, you may want to remove duplicates from those supporters. @@ -162,13 +158,12 @@ def self._full_search(np_id, query) def self.tag_joins_only_for_nonprofit_query(np_id) Qx.select("tag_joins.id, tag_joins.supporter_id, tag_joins.tag_master_id") - .from(:tag_joins) - .join(:supporters, "supporters.id = tag_joins.supporter_id") + .from(:tag_joins) + .join(:supporters, "supporters.id = tag_joins.supporter_id") end def self.build_tag_query(np_id) - - tags_query = Qx.select("tag_joins.supporter_id", "ARRAY_AGG(tag_masters.id) AS ids", "ARRAY_AGG(tag_masters.name::text) AS names") + Qx.select("tag_joins.supporter_id", "ARRAY_AGG(tag_masters.id) AS ids", "ARRAY_AGG(tag_masters.name::text) AS names") .from(:tag_joins) .join(:tag_masters, "tag_masters.id=tag_joins.tag_master_id") .group_by("tag_joins.supporter_id") @@ -178,18 +173,18 @@ def self.build_tag_query(np_id) # Perform all filters and search for /nonprofits/id/supporters dashboard and export def self.full_filter_expr(np_id, query) payments_subquery = - Qx.select("supporter_id", "SUM(gross_amount)", "MAX(date) AS max_date", "MIN(date) AS min_date", "COUNT(*) AS count") - .from( + Qx.select("supporter_id", "SUM(gross_amount)", "MAX(date) AS max_date", "MIN(date) AS min_date", "COUNT(*) AS count") + .from( Qx.select("supporter_id", "date", "gross_amount") - .from(:nonprofit_payments) - .join(Qx.select('id') - .from(:supporters) - .as("payments_to_supporters"), "payments_to_supporters.id = nonprofit_payments.supporter_id" - ) - .as("outer_from_payment_to_supporter") - .parse) - .group_by(:supporter_id) - .as(:payments) + .from(:nonprofit_payments) + .join(Qx.select("id") + .from(:supporters) + .as("payments_to_supporters"), "payments_to_supporters.id = nonprofit_payments.supporter_id") + .as("outer_from_payment_to_supporter") + .parse + ) + .group_by(:supporter_id) + .as(:payments) # tags_subquery = Qx.select("tag_joins.supporter_id", "ARRAY_AGG(tag_masters.id) AS ids", "ARRAY_AGG(tag_masters.name::text) AS names") # .from(:tag_joins) @@ -201,7 +196,7 @@ def self.full_filter_expr(np_id, query) tags_subquery = build_tag_query(np_id) np_queries = NonprofitQueryGenerator.new(np_id) - expr = Qx.select('supporters.id') + expr = Qx.select("supporters.id") .with(:nonprofits, np_queries.nonprofits) .with(:tag_masters, np_queries.tag_masters) .with(:supporters, np_queries.supporters) @@ -209,54 +204,54 @@ def self.full_filter_expr(np_id, query) .with(:nonprofit_payments, np_queries.payments) .with(:tag_joins, np_queries.tag_joins_through_supporters) .from(:supporters) - .join('nonprofits', 'nonprofits.id=supporters.nonprofit_id') + .join("nonprofits", "nonprofits.id=supporters.nonprofit_id") .left_join( - [tags_subquery, "tags.supporter_id=supporters.id"], - [payments_subquery, "payments.supporter_id=supporters.id"] - ) - .order_by('payments.max_date DESC NULLS LAST') + [tags_subquery, "tags.supporter_id=supporters.id"], + [payments_subquery, "payments.supporter_id=supporters.id"] + ) + .order_by("payments.max_date DESC NULLS LAST") if query[:last_payment_after].present? - expr = expr.and_where("payments.max_date > timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $d))", d: Chronic.parse(query[:last_payment_after]).beginning_of_day) + expr = expr.and_where("payments.max_date > timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $d))", d: Chronic.parse(query[:last_payment_after]).beginning_of_day) end if query[:last_payment_before].present? - expr = expr.and_where("payments.max_date < timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $d))", d: Chronic.parse(query[:last_payment_before]).beginning_of_day) + expr = expr.and_where("payments.max_date < timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $d))", d: Chronic.parse(query[:last_payment_before]).beginning_of_day) end if query[:first_payment_after].present? - expr = expr.and_where("payments.min_date > timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $d))", d: Chronic.parse(query[:first_payment_after]).beginning_of_day) + expr = expr.and_where("payments.min_date > timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $d))", d: Chronic.parse(query[:first_payment_after]).beginning_of_day) end if query[:first_payment_before].present? - expr = expr.and_where("payments.min_date < timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $d))", d: Chronic.parse(query[:first_payment_before]).beginning_of_day) + expr = expr.and_where("payments.min_date < timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $d))", d: Chronic.parse(query[:first_payment_before]).beginning_of_day) end if query[:total_raised_greater_than_or_equal].present? - expr = expr.and_where("payments.sum >= $amount", amount: query[:total_raised_greater_than_or_equal].to_s.gsub(/[^\d.]/, '').to_i * 100) + expr = expr.and_where("payments.sum >= $amount", amount: query[:total_raised_greater_than_or_equal].to_s.gsub(/[^\d.]/, "").to_i * 100) end if query[:total_raised_less_than].present? - expr = expr.and_where("payments.sum < $amount OR payments.supporter_id IS NULL", amount: query[:total_raised_less_than].to_s.gsub(/[^\d.]/, '').to_i * 100) + expr = expr.and_where("payments.sum < $amount OR payments.supporter_id IS NULL", amount: query[:total_raised_less_than].to_s.gsub(/[^\d.]/, "").to_i * 100) end - if ['week', 'month', 'quarter', 'year'].include? query[:has_contributed_during] - d = Time.current.send('beginning_of_' + query[:has_contributed_during]) - expr = expr.and_where("payments.max_date >= timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $d))", d: d) + if ["week", "month", "quarter", "year"].include? query[:has_contributed_during] + d = Time.current.send("beginning_of_" + query[:has_contributed_during]) + expr = expr.and_where("payments.max_date >= timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $d))", d: d) end - if ['week', 'month', 'quarter', 'year'].include? query[:has_not_contributed_during] - d = Time.current.send('beginning_of_' + query[:has_not_contributed_during]) - expr = expr.and_where("payments.count = 0 OR payments.max_date <= timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $d))", d: d) + if ["week", "month", "quarter", "year"].include? query[:has_not_contributed_during] + d = Time.current.send("beginning_of_" + query[:has_not_contributed_during]) + expr = expr.and_where("payments.count = 0 OR payments.max_date <= timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $d))", d: d) end if query[:MAX_payment_before].present? date_ago = Timespan::TimeUnits[query[:MAX_payment_before]].utc - expr = expr.and_where("payments.max_date < timezone(COALESCE(nonprofits.timezone, \'UTC\'), timezone(\'UTC\', $date)) OR payments.count = 0", date: date_ago) + expr = expr.and_where("payments.max_date < timezone(COALESCE(nonprofits.timezone, 'UTC'), timezone('UTC', $date)) OR payments.count = 0", date: date_ago) end if query[:search].present? - expr = expr.and_where(%Q( + expr = expr.and_where(%( supporters.fts @@ websearch_to_tsquery('english', $search) OR ( supporters.phone IS NOT NULL AND supporters.phone != '' - AND supporters.phone_index IS NOT NULL + AND supporters.phone_index IS NOT NULL AND supporters.phone_index != '' AND supporters.phone_index = (regexp_replace($search, '\\D','', 'g')) ) - ), search: query[:search], old_search: '%' + query[:search] + '%') + ), search: query[:search], old_search: "%" + query[:search] + "%") end if query[:notes].present? notes_subquery = Qx.select("STRING_AGG(content, ' ') as content, supporter_id") @@ -279,9 +274,9 @@ def self.full_filter_expr(np_id, query) end if query[:anonymous].present? - exprt = expr.and_where('COALESCE(supporters.anonymous, false)') + expr.and_where("COALESCE(supporters.anonymous, false)") end - + if query[:recurring].present? rec_ps_subquery = Qx.select("nonprofit_payments.count", "nonprofit_payments.supporter_id") .from(:nonprofit_payments) @@ -289,17 +284,17 @@ def self.full_filter_expr(np_id, query) .group_by("nonprofit_payments.supporter_id") .as(:rec_ps) expr = expr.add_left_join(rec_ps_subquery, "rec_ps.supporter_id=supporters.id") - .and_where('rec_ps.count > 0') + .and_where("rec_ps.count > 0") end if query[:ids].present? expr = expr.and_where("supporters.id IN ($ids)", ids: query[:ids].split(",").map(&:to_i)) end if query[:select].present? - expr = expr.select(*query[:select].split(",").map{|x| Qx.quote_ident(x)}) + expr = expr.select(*query[:select].split(",").map { |x| Qx.quote_ident(x) }) end # Sort by supporters who have all of the list of tag names if query[:tags].present? - tag_ids = (query[:tags].is_a?(String) ? query[:tags].split(',') : query[:tags]).map(&:to_i) + tag_ids = (query[:tags].is_a?(String) ? query[:tags].split(",") : query[:tags]).map(&:to_i) expr = expr.and_where("tags.ids @> ARRAY[$tag_ids]", tag_ids: tag_ids) end if query[:campaign_id].present? @@ -314,20 +309,21 @@ def self.full_filter_expr(np_id, query) if query[:event_id].present? select_tickets_supporters = Qx.select("event_ticket_supporters.supporter_id") - .from( - "#{Qx.select("MAX(tickets.event_id) AS event_id", "tickets.supporter_id") + .from( + "#{Qx.select("MAX(tickets.event_id) AS event_id", "tickets.supporter_id") .from(:tickets) .where("event_id = $event_id", event_id: query[:event_id]) - .group_by(:supporter_id).as('event_ticket_supporters').parse}" - ) + .group_by(:supporter_id).as("event_ticket_supporters").parse}" + ) select_donation_supporters = - Qx.select("event_donation_supporters.supporter_id") - .from( - "#{Qx.select("MAX(donations.event_id) AS event_id", "donations.supporter_id") + Qx.select("event_donation_supporters.supporter_id") + .from( + "#{Qx.select("MAX(donations.event_id) AS event_id", "donations.supporter_id") .from(:donations) - .where("event_id = $event_id", event_id: query[:event_id] ) - .group_by(:supporter_id).as('event_donation_supporters').parse}") + .where("event_id = $event_id", event_id: query[:event_id]) + .group_by(:supporter_id).as("event_donation_supporters").parse}" + ) union_expr = "( #{select_tickets_supporters.parse} @@ -336,40 +332,39 @@ def self.full_filter_expr(np_id, query) ) AS event_supporters" expr = expr - .add_join( - union_expr, - "event_supporters.supporter_id=supporters.id" - ) + .add_join( + union_expr, + "event_supporters.supporter_id=supporters.id" + ) end - if ['asc', 'desc'].include? query[:sort_name] + if ["asc", "desc"].include? query[:sort_name] expr = expr.order_by(["supporters.name", query[:sort_name]]) end - if ['asc', 'desc'].include? query[:sort_contributed] - expr = expr.and_where("payments.sum > 0").order_by(["payments.sum", query[:sort_contributed]]) + if ["asc", "desc"].include? query[:sort_contributed] + expr = expr.and_where("payments.sum > 0").order_by(["payments.sum", query[:sort_contributed]]) end - if ['asc', 'desc'].include? query[:sort_last_payment] + if ["asc", "desc"].include? query[:sort_last_payment] expr = expr.order_by(["payments.max_date", "#{query[:sort_last_payment].upcase} NULLS LAST"]) end - return expr + expr end - def self.for_export_enumerable(npo_id, query, chunk_limit=15000) - ParamValidation.new({npo_id: npo_id, query:query}, {npo_id: {required: true, is_int: true}, - query: {required:true, is_hash: true}}) + def self.for_export_enumerable(npo_id, query, chunk_limit = 15000) + ParamValidation.new({npo_id: npo_id, query: query}, {npo_id: {required: true, is_int: true}, + query: {required: true, is_hash: true}}) - return QxQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| + QxQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| get_chunk_of_export(npo_id, query, offset, limit, skip_header) end - end - def self.get_chunk_of_export(np_id, query, offset=nil, limit=nil, skip_header=false) - return QxQueryChunker.get_chunk_of_query(offset, limit, skip_header) do + def self.get_chunk_of_export(np_id, query, offset = nil, limit = nil, skip_header = false) + QxQueryChunker.get_chunk_of_query(offset, limit, skip_header) do expr = full_filter_expr(np_id, query) selects = supporter_export_selections.concat([ - '(payments.sum / 100)::money::text AS total_contributed', - 'supporters.id AS id' - ]) + "(payments.sum / 100)::money::text AS total_contributed", + "supporters.id AS id" + ]) if query[:export_custom_fields] # Add a select/csv-column for every custom field master for this nonprofit # and add a left join for every custom field master @@ -378,67 +373,63 @@ def self.get_chunk_of_export(np_id, query, offset=nil, limit=nil, skip_header=fa # FROM supporters # LEFT JOIN custom_field_joins AS export_cfj_Employer ON export_cfj_Employer.supporter_id=supporters.id AND export_cfj_Employer.custom_field_master_id=99 # ... - ids = query[:export_custom_fields].split(',').map(&:to_i) + ids = query[:export_custom_fields].split(",").map(&:to_i) if ids.any? cfms = Qx.select("name", "id").from(:custom_field_masters).where(nonprofit_id: np_id).and_where("id IN ($ids)", ids: ids).ex cfms.compact.map do |cfm| - table_alias = "cfjs_#{cfm['name'].gsub(/\$/, "")}" + table_alias = "cfjs_#{cfm["name"].delete("$")}" table_alias_quot = "\"#{table_alias}\"" field_join_subq = Qx.select("STRING_AGG(value, ',') as value", "supporter_id") - .from("custom_field_joins") - .join("custom_field_masters" , "custom_field_masters.id=custom_field_joins.custom_field_master_id") - .where("custom_field_masters.id=$id", id: cfm['id']) - .group_by(:supporter_id) - .as(table_alias) + .from("custom_field_joins") + .join("custom_field_masters", "custom_field_masters.id=custom_field_joins.custom_field_master_id") + .where("custom_field_masters.id=$id", id: cfm["id"]) + .group_by(:supporter_id) + .as(table_alias) expr.add_left_join(field_join_subq, "#{table_alias_quot}.supporter_id=supporters.id") - selects = selects.concat(["#{table_alias_quot}.value AS \"#{cfm['name']}\""]) + selects = selects.concat(["#{table_alias_quot}.value AS \"#{cfm["name"]}\""]) end end end + get_last_payment_query = Qx.select("supporter_id", "MAX(date) AS date") + .from(:nonprofit_payments) + .group_by("supporter_id") + .as("last_payment") - get_last_payment_query = Qx.select('supporter_id', "MAX(date) AS date") - .from(:nonprofit_payments) - .group_by("supporter_id") - .as("last_payment") - - expr.add_left_join(get_last_payment_query, 'last_payment.supporter_id = supporters.id') + expr.add_left_join(get_last_payment_query, "last_payment.supporter_id = supporters.id") selects = selects.concat(['last_payment.date as "Last Payment Received"']) - supporter_note_query = Qx.select("STRING_AGG(supporter_notes.created_at || ': ' || supporter_notes.content, '\r\n' ORDER BY supporter_notes.created_at DESC) as notes", "supporter_notes.supporter_id") - .from(:supporter_notes) - .group_by('supporter_notes.supporter_id') - .as("supporter_note_query") + .from(:supporter_notes) + .group_by("supporter_notes.supporter_id") + .as("supporter_note_query") - expr.add_left_join(supporter_note_query, 'supporter_note_query.supporter_id=supporters.id') + expr.add_left_join(supporter_note_query, "supporter_note_query.supporter_id=supporters.id") selects = selects.concat(["supporter_note_query.notes AS notes"]).concat(["ARRAY_TO_STRING(tags.names, ',') as tags"]) - expr.select(selects) end end - def self.supporter_note_export_enumerable(npo_id, query, chunk_limit=15000) - ParamValidation.new({npo_id: npo_id, query:query}, {npo_id: {required: true, is_int: true}, - query: {required:true, is_hash: true}}) + def self.supporter_note_export_enumerable(npo_id, query, chunk_limit = 15000) + ParamValidation.new({npo_id: npo_id, query: query}, {npo_id: {required: true, is_int: true}, + query: {required: true, is_hash: true}}) - return QxQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| + QxQueryChunker.for_export_enumerable(chunk_limit) do |offset, limit, skip_header| get_chunk_of_supporter_note_export(npo_id, query, offset, limit, skip_header) end - end - def self.get_chunk_of_supporter_note_export(np_id, query, offset=nil, limit=nil, skip_header=false) - return QxQueryChunker.get_chunk_of_query(offset, limit, skip_header) do + def self.get_chunk_of_supporter_note_export(np_id, query, offset = nil, limit = nil, skip_header = false) + QxQueryChunker.get_chunk_of_query(offset, limit, skip_header) do expr = full_filter_expr(np_id, query) supporter_note_select = [ - 'supporters.id', - 'supporters.email', + "supporters.id", + "supporters.email", 'supporter_notes.created_at as "Note Created At"', 'supporter_notes.content "Note Contents"' ] - expr.add_join(:supporter_notes, 'supporter_notes.supporter_id = supporters.id') + expr.add_join(:supporter_notes, "supporter_notes.supporter_id = supporters.id") expr.select(supporter_note_select) end @@ -448,43 +439,43 @@ def self.get_chunk_of_supporter_note_export(np_id, query, offset=nil, limit=nil, def self.for_export(np_id, query) expr = full_filter_expr(np_id, query) selects = supporter_export_selections.concat([ - '(payments.sum / 100)::money::text AS total_contributed', - 'supporters.id AS id' + "(payments.sum / 100)::money::text AS total_contributed", + "supporters.id AS id" ]) if query[:export_custom_fields] # Add a select/csv-column for every custom field master for this nonprofit # and add a left join for every custom field master - # eg if the npo has a custom field like Employer with id 99, then the query will be - # SELECT export_cfj_Employer.value AS Employer, ... - # FROM supporters + # eg if the npo has a custom field like Employer with id 99, then the query will be + # SELECT export_cfj_Employer.value AS Employer, ... + # FROM supporters # LEFT JOIN custom_field_joins AS export_cfj_Employer ON export_cfj_Employer.supporter_id=supporters.id AND export_cfj_Employer.custom_field_master_id=99 # ... - ids = query[:export_custom_fields].split(',').map(&:to_i) + ids = query[:export_custom_fields].split(",").map(&:to_i) if ids.any? cfms = Qx.select("name", "id").from(:custom_field_masters).where(nonprofit_id: np_id).and_where("id IN ($ids)", ids: ids).ex cfms.compact.map do |cfm| - table_alias = "cfjs_#{cfm['name'].gsub(/\$/, "")}" + table_alias = "cfjs_#{cfm["name"].delete("$")}" table_alias_quot = "\"#{table_alias}\"" field_join_subq = Qx.select("STRING_AGG(value, ',') as value", "supporter_id") .from("custom_field_joins") - .join("custom_field_masters" , "custom_field_masters.id=custom_field_joins.custom_field_master_id") - .where("custom_field_masters.id=$id", id: cfm['id']) + .join("custom_field_masters", "custom_field_masters.id=custom_field_joins.custom_field_master_id") + .where("custom_field_masters.id=$id", id: cfm["id"]) .group_by(:supporter_id) .as(table_alias) expr.add_left_join(field_join_subq, "#{table_alias_quot}.supporter_id=supporters.id") - selects = selects.concat(["#{table_alias_quot}.value AS \"#{cfm['name']}\""]) + selects = selects.concat(["#{table_alias_quot}.value AS \"#{cfm["name"]}\""]) end end end supporter_note_query = Qx.select("STRING_AGG(supporter_notes.created_at || ': ' || supporter_notes.content, '\r\n' ORDER BY supporter_notes.created_at DESC) as notes", "supporter_notes.supporter_id") .from(:supporter_notes) - .group_by('supporter_notes.supporter_id') + .group_by("supporter_notes.supporter_id") .as("supporter_note_query") - expr.add_left_join(supporter_note_query, 'supporter_note_query.supporter_id=supporters.id') + expr.add_left_join(supporter_note_query, "supporter_note_query.supporter_id=supporters.id") selects = selects.concat(["supporter_note_query.notes AS notes"]) - expr.select(selects).execute(format: 'csv') + expr.select(selects).execute(format: "csv") end def self.supporter_export_selections(*remove) @@ -503,7 +494,7 @@ def self.supporter_export_selections(*remove) "supporters.country \"Country\"", "supporters.id \"Supporter ID\"" ] - if (!remove.include? :anonymous) + if !remove.include? :anonymous result = result.push("supporters.anonymous \"Anonymous?\"") end result @@ -517,7 +508,7 @@ def self.dupes_expr(np_id) .from(:supporters) .where("nonprofit_id=$id", id: np_id) .and_where("NOT deleted") - .having('COUNT(id) > 1') + .having("COUNT(id) > 1") end # Merge on exact supporter and email match @@ -531,7 +522,7 @@ def self.dupes_on_email(np_id, strict_mode = true) .and_where("email IS NOT NULL") .and_where("email != ''") .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end @@ -541,23 +532,23 @@ def self.dupes_on_name(np_id, strict_mode = true) dupes_expr(np_id) .and_where("name IS NOT NULL") .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end # Find all duplicate supporters that match on both name/email # @return [Array[Array]] an array containing arrays of the ids of duplicate supporters def self.dupes_on_name_and_email(np_id, strict_mode = true) - group_by_clause = (strict_mode ? [strict_name_match, 'email'] : [loose_name_match, loose_email_match]).join(', ') + group_by_clause = (strict_mode ? [strict_name_match, "email"] : [loose_name_match, loose_email_match]).join(", ") dupes_expr(np_id) .and_where("name IS NOT NULL AND name != '' AND email IS NOT NULL AND email != ''") .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end def self.dupes_on_name_and_phone(np_id, strict_mode = true) - group_by_clause = [(strict_mode ? strict_name_match : loose_name_match), 'phone_index'].join(', ') + group_by_clause = [(strict_mode ? strict_name_match : loose_name_match), "phone_index"].join(", ") dupes_expr(np_id) .and_where( "name IS NOT NULL\ @@ -566,12 +557,12 @@ def self.dupes_on_name_and_phone(np_id, strict_mode = true) AND phone_index != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end def self.dupes_on_name_and_phone_and_address(np_id, strict_mode = true) - group_by_clause = (strict_mode ? [strict_name_match, strict_address_match] : [loose_name_match, loose_address_match]).append("phone_index").join(', ') + group_by_clause = (strict_mode ? [strict_name_match, strict_address_match] : [loose_name_match, loose_address_match]).append("phone_index").join(", ") dupes_expr(np_id) .and_where( "name IS NOT NULL\ @@ -582,12 +573,12 @@ def self.dupes_on_name_and_phone_and_address(np_id, strict_mode = true) AND address != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end def self.dupes_on_phone_and_email_and_address(np_id, strict_mode = true) - group_by_clause = (strict_mode ? [strict_address_match, strict_email_match] : [loose_address_match, loose_email_match]).append("phone_index").join(', ') + group_by_clause = (strict_mode ? [strict_address_match, strict_email_match] : [loose_address_match, loose_email_match]).append("phone_index").join(", ") dupes_expr(np_id) .and_where( "phone_index IS NOT NULL \ @@ -598,7 +589,7 @@ def self.dupes_on_phone_and_email_and_address(np_id, strict_mode = true) AND address != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end @@ -610,12 +601,12 @@ def self.dupes_on_address(np_id, strict_mode = true) AND address != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end def self.dupes_on_name_and_address(np_id, strict_mode = true) - group_by_clause = (strict_mode ? [strict_name_match, strict_address_match] : [loose_name_match, loose_address_match]).join(', ') + group_by_clause = (strict_mode ? [strict_name_match, strict_address_match] : [loose_name_match, loose_address_match]).join(", ") dupes_expr(np_id) .and_where( "name IS NOT NULL\ @@ -624,7 +615,7 @@ def self.dupes_on_name_and_address(np_id, strict_mode = true) AND address != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end @@ -636,8 +627,8 @@ def self.dupes_on_last_name_and_address(np_id) AND address IS NOT NULL \ AND address != ''" ) - .group_by(self.calculated_last_name + " || '_____' || address") - .execute(format: 'csv')[1..-1] + .group_by(calculated_last_name + " || '_____' || address") + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end @@ -649,13 +640,13 @@ def self.dupes_on_last_name_and_address_and_email(np_id) AND address IS NOT NULL \ AND address != ''" ) - .group_by(self.calculated_last_name + " || '_____' || address || '_____' || COALESCE(email, '')") - .execute(format: 'csv')[1..-1] + .group_by(calculated_last_name + " || '_____' || address || '_____' || COALESCE(email, '')") + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end def self.dupes_on_phone_and_email(np_id, strict_mode = true) - group_by_clause = [(strict_mode ? strict_email_match : loose_email_match), "phone_index"].join(', ') + group_by_clause = [(strict_mode ? strict_email_match : loose_email_match), "phone_index"].join(", ") dupes_expr(np_id) .and_where( "phone_index IS NOT NULL \ @@ -664,7 +655,7 @@ def self.dupes_on_phone_and_email(np_id, strict_mode = true) AND email != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end @@ -676,7 +667,7 @@ def self.dupes_on_address_without_zip_code(np_id, strict_mode = true) AND address != ''" ) .group_by(group_by_clause) - .execute(format: 'csv')[1..-1] + .execute(format: "csv")[1..-1] .map { |arr_group| arr_group.flatten.sort } end @@ -702,7 +693,7 @@ def self.loose_address_match def self.loose_address_match_chunks ["regexp_replace (lower(address),'[^0-9a-z]','','g')", - "substring(zip_code from '(([0-9]+.*)*[0-9]+)')"] + "substring(zip_code from '(([0-9]+.*)*[0-9]+)')"] end def self.loose_name_match @@ -728,17 +719,17 @@ def self.calculated_last_name # Only including payments for the given year def self.end_of_year_donor_report(np_id, year) supporter_expr = Qexpr.new - .select( supporter_export_selections.concat(["(payments.sum::numeric / 100.0)::money::text AS \"Total Contributions #{year}\"", "supporters.id"]) ) + .select(supporter_export_selections.concat(["(payments.sum::numeric / 100.0)::money::text AS \"Total Contributions #{year}\"", "supporters.id"])) .from(:supporters) .join(Qexpr.new .select("SUM(gross_amount)", "supporter_id") .from(:payments) .group_by(:supporter_id) .where("date >= $date", date: "#{year}-01-01 00:00:00 UTC") - .where("date < $date", date: "#{year+1}-01-01 00:00:00 UTC") + .where("date < $date", date: "#{year + 1}-01-01 00:00:00 UTC") .as(:payments), "payments.supporter_id=supporters.id") - .where('payments.sum > 25000') - .as('supporters') + .where("payments.sum > 25000") + .as("supporters") Psql.execute_vectors( Qexpr.new @@ -749,20 +740,19 @@ def self.end_of_year_donor_report(np_id, year) 'payments.towards AS "Designation"' ) .from(:payments) - .join(supporter_expr, 'supporters.id = payments.supporter_id') - .where('payments.nonprofit_id = $id', id: np_id) - .where('payments.date >= $date', date: "#{year}-01-01 00:00:00 UTC") - .where('payments.date < $date', date: "#{year+1}-01-01 00:00:00 UTC") + .join(supporter_expr, "supporters.id = payments.supporter_id") + .where("payments.nonprofit_id = $id", id: np_id) + .where("payments.date >= $date", date: "#{year}-01-01 00:00:00 UTC") + .where("payments.date < $date", date: "#{year + 1}-01-01 00:00:00 UTC") .order_by("supporters.\"MAX Name\", payments.date DESC") ) end - # returns an array of common selects for supporters # which gets concated with an optional array of additional selects # used for merging supporters, crm profile and info card def self.profile_selects(arr = []) - ["supporters.id", + ["supporters.id", "supporters.name", "supporters.email", "supporters.address", @@ -774,16 +764,14 @@ def self.profile_selects(arr = []) "supporters.phone"] + arr end - # used on crm profile and info card - def self.profile_payments_subquery + def self.profile_payments_subquery Qx.select("supporter_id", "SUM(gross_amount)", "COUNT(id) AS count") .from("payments") .group_by("supporter_id") .as("payments") end - # Get a large set of detailed info for a single supporter, to be displayed in # the side panel details of the supporter listing after clicking a row. def self.for_crm_profile(npo_id, ids) @@ -798,7 +786,8 @@ def self.for_crm_profile(npo_id, ids) "MAX(full_contact_infos.full_name) AS fc_full_name", "MAX(full_contact_infos.age) AS fc_age", "MAX(full_contact_infos.location_general) AS fc_location_general", - "MAX(full_contact_infos.websites) AS fc_websites"] + "MAX(full_contact_infos.websites) AS fc_websites" + ] Qx.select(*QuerySupporters.profile_selects(selects)) .from("supporters") @@ -806,7 +795,8 @@ def self.for_crm_profile(npo_id, ids) ["donations", "donations.supporter_id=supporters.id"], ["full_contact_infos", "full_contact_infos.supporter_id=supporters.id"], ["recurring_donations", "recurring_donations.donation_id=donations.id"], - [QuerySupporters.profile_payments_subquery, "payments.supporter_id=supporters.id"]) + [QuerySupporters.profile_payments_subquery, "payments.supporter_id=supporters.id"] + ) .group_by("supporters.id") .where("supporters.id IN ($ids)", ids: ids) .and_where("supporters.nonprofit_id = $id", id: npo_id) @@ -814,7 +804,7 @@ def self.for_crm_profile(npo_id, ids) end def self.for_info_card(id) - selects = ["COALESCE(MAX(payments.sum), 0) AS raised"] + selects = ["COALESCE(MAX(payments.sum), 0) AS raised"] Qx.select(*QuerySupporters.profile_selects(selects)) .from("supporters") .left_join([QuerySupporters.profile_payments_subquery, "payments.supporter_id=supporters.id"]) @@ -831,7 +821,6 @@ def self.merge_data(ids) .execute end - def self.year_aggregate_report(npo_id, time_range_params) npo_id = npo_id.to_i @@ -843,7 +832,7 @@ def self.year_aggregate_report(npo_id, time_range_params) ParamValidation.new({npo_id: npo_id}, { npo_id: {required: true, is_integer: true} }) - aggregate_dons = %Q( + aggregate_dons = %( array_to_string( array_agg( payments.date::date || ' ' || @@ -861,78 +850,73 @@ def self.year_aggregate_report(npo_id, time_range_params) "AVG(payments.gross_amount::numeric / 100)::text::money AS \"Average Payment\"", aggregate_dons ]) - return Qx.select(selects) + Qx.select(selects) .from(:supporters) - .join("payments", "payments.supporter_id=supporters.id AND payments.date::date >= $min_date AND payments.date::date < $max_date",:min_date => min_date.to_date, :max_date => max_date.to_date ) - .where('supporters.nonprofit_id=$id', id: npo_id) + .join("payments", "payments.supporter_id=supporters.id AND payments.date::date >= $min_date AND payments.date::date < $max_date", min_date: min_date.to_date, max_date: max_date.to_date) + .where("supporters.nonprofit_id=$id", id: npo_id) .group_by("supporters.id") .order_by("substring(trim(supporters.name) from '^.+ ([^\s]+)$')") - .execute(format: 'csv') + .execute(format: "csv") end - def self.get_min_or_max_dates_for_range(time_range_params) - begin - if (time_range_params[:year]) - if (time_range_params[:year].is_a?(Integer)) - return DateTime.new(time_range_params[:year], 1, 1), DateTime.new(time_range_params[:year]+1, 1, 1) - end - if (time_range_params[:year].is_a?(String)) - wip = time_range_params[:year].to_i - return DateTime.new(wip, 1, 1), DateTime.new(wip+1, 1, 1) - end + if time_range_params[:year] + if time_range_params[:year].is_a?(Integer) + return DateTime.new(time_range_params[:year], 1, 1), DateTime.new(time_range_params[:year] + 1, 1, 1) end - if (time_range_params[:start]) - start = parse_convert_datetime(time_range_params[:start]) - if (time_range_params[:end]) - end_datetime = parse_convert_datetime(time_range_params[:end]) - end - - unless start.nil? - return start, end_datetime ? end_datetime : start + 1.year - end + if time_range_params[:year].is_a?(String) + wip = time_range_params[:year].to_i + return DateTime.new(wip, 1, 1), DateTime.new(wip + 1, 1, 1) end - raise ArgumentError.new("no valid time range provided") - rescue - raise ArgumentError.new("no valid time range provided") end + if time_range_params[:start] + start = parse_convert_datetime(time_range_params[:start]) + if time_range_params[:end] + end_datetime = parse_convert_datetime(time_range_params[:end]) + end + unless start.nil? + return start, end_datetime || start + 1.year + end + end + raise ArgumentError.new("no valid time range provided") + rescue + raise ArgumentError.new("no valid time range provided") end def self.tag_joins(nonprofit_id, supporter_id) - Qx.select('tag_masters.id', 'tag_masters.name') - .from('tag_joins') - .left_join('tag_masters', 'tag_masters.id = tag_joins.tag_master_id') + Qx.select("tag_masters.id", "tag_masters.name") + .from("tag_joins") + .left_join("tag_masters", "tag_masters.id = tag_joins.tag_master_id") .where( - ['tag_joins.supporter_id = $id', id: supporter_id], - ['coalesce(tag_masters.deleted, FALSE) = FALSE'], - ['tag_masters.nonprofit_id = $id', id: nonprofit_id] + ["tag_joins.supporter_id = $id", id: supporter_id], + ["coalesce(tag_masters.deleted, FALSE) = FALSE"], + ["tag_masters.nonprofit_id = $id", id: nonprofit_id] ) .execute end # this is inefficient, don't use in live code def self.find_supporters_with_multiple_recurring_donations_evil_way(npo_id) - supporters = Supporter.where('supporters.nonprofit_id = ?', npo_id).includes(:recurring_donations) - supporters.select{|s| s.recurring_donations.length > 1} + supporters = Supporter.where("supporters.nonprofit_id = ?", npo_id).includes(:recurring_donations) + supporters.select { |s| s.recurring_donations.length > 1 } end # this is inefficient, don't use in live code def self.find_supporters_with_multiple_active_recurring_donations_evil_way(npo_id) - supporters = Supporter.where('supporters.nonprofit_id = ?', npo_id).includes(:recurring_donations) - supporters.select{|s| s.recurring_donations.select{|rd| rd.active }.length > 1} + supporters = Supporter.where("supporters.nonprofit_id = ?", npo_id).includes(:recurring_donations) + supporters.select { |s| s.recurring_donations.select { |rd| rd.active }.length > 1 } end def self.parse_convert_datetime(date) - if (date.is_a?(DateTime)) + if date.is_a?(DateTime) return date end - if (date.is_a?(Date)) + if date.is_a?(Date) return date.to_datetime end - if(date.is_a?(String)) - return DateTime.parse(date) + if date.is_a?(String) + DateTime.parse(date) end end end - diff --git a/app/legacy_lib/query_ticket_levels.rb b/app/legacy_lib/query_ticket_levels.rb index b20dd5ae6..a710cfb4e 100644 --- a/app/legacy_lib/query_ticket_levels.rb +++ b/app/legacy_lib/query_ticket_levels.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'hashie' +require "hashie" module QueryTicketLevels - def self.gross_amount_from_tickets(tickets, discount_id) - amounts = TicketLevel.where('id IN (?)', tickets.map{|h| h['ticket_level_id']}).map{|i| [i.id, i.amount]}.to_h - total = tickets.map{|t| amounts[t['ticket_level_id'].to_i].to_i * t['quantity'].to_i}.sum + amounts = TicketLevel.where("id IN (?)", tickets.map { |h| h["ticket_level_id"] }).map { |i| [i.id, i.amount] }.to_h + total = tickets.map { |t| amounts[t["ticket_level_id"].to_i].to_i * t["quantity"].to_i }.sum if discount_id perc = EventDiscount.find(discount_id).percent @@ -13,7 +12,6 @@ def self.gross_amount_from_tickets(tickets, discount_id) end total end - def self.with_event_id(event_id, is_admin) expr = Qx.select("ticket_levels.*", "SUM(tickets.quantity) AS quantity") @@ -27,15 +25,15 @@ def self.with_event_id(event_id, is_admin) expr = expr.and_where("coalesce(ticket_levels.admin_only, FALSE) = FALSE") end - return expr.execute + expr.execute end def self.verify_tickets_available(tickets) - tickets.each{|data| - if (data[:quantity] != 0) + tickets.each { |data| + if data[:quantity] != 0 tl = TicketLevel.find(data[:ticket_level_id]) if tl.limit && tl.limit > 0 - already_sold = Ticket.where('ticket_level_id = ?', data[:ticket_level_id]).sum('tickets.quantity') + already_sold = Ticket.where("ticket_level_id = ?", data[:ticket_level_id]).sum("tickets.quantity") unless (already_sold + data[:quantity]) <= tl.limit raise NotEnoughQuantityError.new(TicketLevel, data[:ticket_level_id], data[:quantity], "Oops! We sold out some of the tickets you wanted before ordering. Please refresh to see what tickets are still available.") end @@ -43,5 +41,4 @@ def self.verify_tickets_available(tickets) end } end - end diff --git a/app/legacy_lib/query_tickets.rb b/app/legacy_lib/query_tickets.rb index d28ec839f..32daa5423 100644 --- a/app/legacy_lib/query_tickets.rb +++ b/app/legacy_lib/query_tickets.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryTickets - def self.attendees_expr(event_id, query) expr = Qexpr.new - .from('tickets') + .from("tickets") .where("coalesce(tickets.deleted, FALSE) = FALSE") .left_outer_join("event_discounts", "event_discounts.id=tickets.event_discount_id") .left_outer_join( Qexpr.new.select("*") .from(:supporters).group_by("id").as("supporters"), - 'tickets.supporter_id=supporters.id' + "tickets.supporter_id=supporters.id" ) .left_outer_join("charges", "charges.id=tickets.charge_id") .left_outer_join( @@ -22,51 +21,50 @@ def self.attendees_expr(event_id, query) .left_outer_join( Qexpr.new.select("id", "name", "amount") .from(:ticket_levels).group_by("id").as("ticket_levels"), - 'tickets.ticket_level_id=ticket_levels.id' + "tickets.ticket_level_id=ticket_levels.id" ) .left_outer_join( - Qexpr.new.select('token', 'tokenizable_id').from(:source_tokens).group_by( 'token', 'tokenizable_id').as('source_tokens'), - 'tickets.source_token_id=source_tokens.token' + Qexpr.new.select("token", "tokenizable_id").from(:source_tokens).group_by("token", "tokenizable_id").as("source_tokens"), + "tickets.source_token_id=source_tokens.token" ) .left_outer_join( - # TODO this does not support anything other than cards! - Qexpr.new.select('id', 'name').from(:cards).group_by('id', 'name').as('cards'), - 'source_tokens.tokenizable_id = cards.id' + # TODO this does not support anything other than cards! + Qexpr.new.select("id", "name").from(:cards).group_by("id", "name").as("cards"), + "source_tokens.tokenizable_id = cards.id" ) .left_outer_join( - Qexpr.new.select('supporter_id', 'MAX(event_id) AS event_id', 'SUM(amount) AS total_amount') + Qexpr.new.select("supporter_id", "MAX(event_id) AS event_id", "SUM(amount) AS total_amount") .from(:donations).where("event_id=$id", id: event_id).group_by("supporter_id").as(:donations), "donations.supporter_id=supporters.id AND donations.event_id=$id", id: event_id ) - .where('tickets.event_id=$id', id: event_id) - .order_by('tickets.bid_id DESC') + .where("tickets.event_id=$id", id: event_id) + .order_by("tickets.bid_id DESC") if query[:search].present? - query[:search] = "%#{query[:search].downcase.split(' ').join('%')}%" - expr = expr.where(%Q( + query[:search] = "%#{query[:search].downcase.split(" ").join("%")}%" + expr = expr.where(%( lower(supporters.name) LIKE $search OR lower(supporters.email) LIKE $search OR lower(ticket_levels.name) LIKE $search - ), search: '%' + query[:search] + '%') + ), search: "%" + query[:search] + "%") end - if ['asc', 'desc'].include? query[:sort_attendee] + if ["asc", "desc"].include? query[:sort_attendee] expr = expr.order_by("lower(supporters.name) #{query[:sort_attendee]} NULLS LAST") end - if ['asc', 'desc'].include? query[:sort_id] + if ["asc", "desc"].include? query[:sort_id] expr = expr.order_by("tickets.bid_id #{query[:sort_id]}") end - if ['asc', 'desc'].include? query[:sort_note] + if ["asc", "desc"].include? query[:sort_note] expr = expr.order_by("lower(tickets.note) #{query[:sort_note]} NULLS LAST") end - if ['asc', 'desc'].include? query[:sort_ticket_level] + if ["asc", "desc"].include? query[:sort_ticket_level] expr = expr.order_by("lower(ticket_levels.name) #{query[:sort_ticket_level]} NULLS LAST") end - if ['asc', 'desc'].include? query[:sort_donation] + if ["asc", "desc"].include? query[:sort_donation] expr = expr.order_by("total_donations #{query[:sort_donation]} NULLS LAST") end - return expr + expr end - def self.attendees_list(event_id, query) nonprofit = Event.find(event_id).nonprofit limit = 30 @@ -81,24 +79,23 @@ def self.attendees_list(event_id, query) total_count = Psql.execute( Qexpr.new.select("COUNT(ts)") .from(attendees_expr(event_id, query) - .remove(:order_by).select('tickets.id'), 'ts') - ).first['count'] + .remove(:order_by).select("tickets.id"), "ts") + ).first["count"] - #TODO this worries me. Seems like a recipe for slow returns... perhaps some caching of the tokens every so often? - data.each{|i| - unless (i['source_token_id'] && QuerySourceToken.source_token_unexpired?(SourceToken.find(i['source_token_id']))) - i['source_token_id'] = nil + # TODO this worries me. Seems like a recipe for slow returns... perhaps some caching of the tokens every so often? + data.each { |i| + unless i["source_token_id"] && QuerySourceToken.source_token_unexpired?(SourceToken.find(i["source_token_id"])) + i["source_token_id"] = nil end } - return { + { data: data, total_count: total_count, remaining: Qexpr.remaining_count(total_count, limit, query[:page]) } end - def self.for_export(event_id, query) data = Psql.execute_vectors( attendees_expr(event_id, query) @@ -115,10 +112,10 @@ def self.for_export(event_id, query) ].concat(QuerySupporters.supporter_export_selections)) ) - data[0].push('Card Saved?') - data.drop(1).each{|i| + data[0].push("Card Saved?") + data.drop(1).each { |i| source_token_id = i[8] - if (source_token_id && QuerySourceToken.source_token_unexpired?(SourceToken.find(source_token_id))) + if source_token_id && QuerySourceToken.source_token_unexpired?(SourceToken.find(source_token_id)) i.push("Yes") else i.push("") @@ -128,46 +125,43 @@ def self.for_export(event_id, query) data end - def self.attendees_list_selection(nonprofit) - ['tickets.id', - 'tickets.bid_id', - 'tickets.checked_in', - 'tickets.quantity', - 'tickets.note', - 'tickets.source_token_id', - 'ticket_levels.name AS ticket_level_name', - '(coalesce(charges.amount, 0) - coalesce(refunds.amount, 0)) AS total_paid', - 'ticket_levels.id AS ticket_level_id', - 'ticket_levels.amount AS ticket_level_amount', - 'event_discounts.percent AS discount_percent', - 'supporters.id AS supporter_id', - 'supporters.name AS name', - 'supporters.email AS email', - "'/nonprofits/#{nonprofit.id}/supporters?sid=' || supporters.id AS supporter_url", - 'coalesce(donations.total_amount, 0) AS total_donations', - 'source_tokens.token AS token', - 'cards.name AS card_name' - ] + ["tickets.id", + "tickets.bid_id", + "tickets.checked_in", + "tickets.quantity", + "tickets.note", + "tickets.source_token_id", + "ticket_levels.name AS ticket_level_name", + "(coalesce(charges.amount, 0) - coalesce(refunds.amount, 0)) AS total_paid", + "ticket_levels.id AS ticket_level_id", + "ticket_levels.amount AS ticket_level_amount", + "event_discounts.percent AS discount_percent", + "supporters.id AS supporter_id", + "supporters.name AS name", + "supporters.email AS email", + "'/nonprofits/#{nonprofit.id}/supporters?sid=' || supporters.id AS supporter_url", + "coalesce(donations.total_amount, 0) AS total_donations", + "source_tokens.token AS token", + "cards.name AS card_name"] end def self.for_event_activities(event_id) selects = [" - CASE - WHEN supporters.anonymous='t' - OR supporters.name='' - OR supporters.name IS NULL - THEN 'A supporter' - ELSE supporters.name - END AS supporter_name", - 'tickets.quantity', 'tickets.created_at'] - return Qx.select(selects.join(',')) + CASE + WHEN supporters.anonymous='t' + OR supporters.name='' + OR supporters.name IS NULL + THEN 'A supporter' + ELSE supporters.name + END AS supporter_name", + "tickets.quantity", "tickets.created_at"] + Qx.select(selects.join(",")) .from(:tickets) - .left_join(:supporters, 'tickets.supporter_id=supporters.id') - .where('tickets.event_id=$id', id: event_id) + .left_join(:supporters, "tickets.supporter_id=supporters.id") + .where("tickets.event_id=$id", id: event_id) .order_by("tickets.created_at desc") .limit(15) .execute end - end diff --git a/app/legacy_lib/query_users.rb b/app/legacy_lib/query_users.rb index 3b6688a31..ae28c6fc7 100644 --- a/app/legacy_lib/query_users.rb +++ b/app/legacy_lib/query_users.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module QueryUsers - # Return all the nonprofit user emails for a given email notification setting # for notification_type in ['payments', 'campaigns', 'events', 'payouts', 'recurring_donations'] def self.nonprofit_user_emails(np_id, notification_type) - raise ArgumentError.new('Invalid notification type') unless QueryEmailSettings::Settings.include?(notification_type) + raise ArgumentError.new("Invalid notification type") unless QueryEmailSettings::Settings.include?(notification_type) Qx.select("users.email") .from("users") .join("roles", "roles.user_id=users.id") @@ -14,24 +13,23 @@ def self.nonprofit_user_emails(np_id, notification_type) .where("email_settings.user_id IS NULL OR email_settings.#{notification_type}=TRUE") .and_where("nonprofits.id=$id", id: np_id) .group_by("users.email") - .execute.map{|h| h['email']} + .execute.map { |h| h["email"] } end # Return all nonprofit emails regardless of email settings - def self.all_nonprofit_user_emails(np_id, roles=[:nonprofit_admin, :nonprofit_user]) - Qx.select('users.email').from('users') - .join('roles', 'roles.user_id = users.id') - .add_join('nonprofits', 'nonprofits.id = roles.host_id AND roles.host_type=\'Nonprofit\'') - .where('nonprofits.id=$id', id: np_id) - .and_where('roles.name IN ($names)', names: roles) - .execute.map{|h| h['email']} + def self.all_nonprofit_user_emails(np_id, roles = [:nonprofit_admin, :nonprofit_user]) + Qx.select("users.email").from("users") + .join("roles", "roles.user_id = users.id") + .add_join("nonprofits", "nonprofits.id = roles.host_id AND roles.host_type='Nonprofit'") + .where("nonprofits.id=$id", id: np_id) + .and_where("roles.name IN ($names)", names: roles) + .execute.map { |h| h["email"] } end # Return an array of email address strings for all users with role of 'super_admin' def self.super_admin_emails Qx.select("users.email").from("users") .join("roles", "roles.user_id=users.id AND roles.name='super_admin'") - .ex.map{|h| h['email']} + .ex.map { |h| h["email"] } end - end diff --git a/app/legacy_lib/qx_query_chunker.rb b/app/legacy_lib/qx_query_chunker.rb index cee3ca0b8..6dd3597cb 100644 --- a/app/legacy_lib/qx_query_chunker.rb +++ b/app/legacy_lib/qx_query_chunker.rb @@ -1 +1 @@ -QxQueryChunker = QexprQueryChunker \ No newline at end of file +QxQueryChunker = QexprQueryChunker diff --git a/app/legacy_lib/reassign_supporter_items.rb b/app/legacy_lib/reassign_supporter_items.rb index b15965977..40402ee9e 100644 --- a/app/legacy_lib/reassign_supporter_items.rb +++ b/app/legacy_lib/reassign_supporter_items.rb @@ -1,77 +1,75 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module ReassignSupporterItems - def self.perform(etap_import) - badly_assigned_items = find_badly_assigned_items(etap_import) - badly_assigned_items.each do |items| - ActiveRecord::Base.transaction do - reassign_journal_entries(items[:supp_through_contact], items[:journal_entries_to_items_with_wrong_supporter], etap_import) - end - end - remaining_badly_assigned_items = find_badly_assigned_items(etap_import) + def self.perform(etap_import) + badly_assigned_items = find_badly_assigned_items(etap_import) + badly_assigned_items.each do |items| + ActiveRecord::Base.transaction do + reassign_journal_entries(items[:supp_through_contact], items[:journal_entries_to_items_with_wrong_supporter], etap_import) + end end + find_badly_assigned_items(etap_import) + end - def self.find_badly_assigned_items(etap_import) - etap_import.e_tap_import_journal_entries.find_each.map do |etije| - supp_through_contact = etije.supporter_through_e_tap_import_contact - if supp_through_contact.blank? - supp_through_contact = ETapImportContact.find_by_account_name(etije.journal_entries_to_items.first.item.supporter.name, etije.journal_entries_to_items.first.item.supporter.email, etije.account_id)&.supporter - end - if etije.journal_entries_to_items.select{|i| i.item.supporter != supp_through_contact}.any? - { - etije: etije, - etije_id: etije.id, - supp_through_contact: supp_through_contact, - journal_entries_to_items_with_wrong_supporter: etije.journal_entries_to_items.select{|i| i.item.supporter != supp_through_contact} - } - else - nil - end - end.compact - end + def self.find_badly_assigned_items(etap_import) + etap_import.e_tap_import_journal_entries.find_each.map do |etije| + supp_through_contact = etije.supporter_through_e_tap_import_contact + if supp_through_contact.blank? + supp_through_contact = ETapImportContact.find_by_account_name(etije.journal_entries_to_items.first.item.supporter.name, etije.journal_entries_to_items.first.item.supporter.email, etije.account_id)&.supporter + end + if etije.journal_entries_to_items.select { |i| i.item.supporter != supp_through_contact }.any? + { + etije: etije, + etije_id: etije.id, + supp_through_contact: supp_through_contact, + journal_entries_to_items_with_wrong_supporter: etije.journal_entries_to_items.select { |i| i.item.supporter != supp_through_contact } + } + end + end.compact + end - def self.reassign_journal_entries(correct_supporter, journal_entries_to_items_with_wrong_supporter, etap_import) - return if correct_supporter.blank? + def self.reassign_journal_entries(correct_supporter, journal_entries_to_items_with_wrong_supporter, etap_import) + return if correct_supporter.blank? - journal_entries_to_items_with_wrong_supporter.each do |journal_entry| - reassign_item(correct_supporter, journal_entry.item, etap_import) - end + journal_entries_to_items_with_wrong_supporter.each do |journal_entry| + reassign_item(correct_supporter, journal_entry.item, etap_import) end + end - def self.reassign_item(correct_supporter, item, etap_import) - activities = find_activities(item) - etap_import.reassignments.create(item: item, source_supporter: item.supporter, target_supporter: correct_supporter) - item.supporter = correct_supporter - item.save! - activities.each do |activity| - etap_import.reassignments.create(item: activity, source_supporter: activity.supporter, target_supporter: correct_supporter) - activity.supporter = correct_supporter - activity.save! - end + def self.reassign_item(correct_supporter, item, etap_import) + activities = find_activities(item) + etap_import.reassignments.create(item: item, source_supporter: item.supporter, target_supporter: correct_supporter) + item.supporter = correct_supporter + item.save! + activities.each do |activity| + etap_import.reassignments.create(item: activity, source_supporter: activity.supporter, target_supporter: correct_supporter) + activity.supporter = correct_supporter + activity.save! end + end - def self.find_activities(item) - attachment_type = item.class.name - if item.is_a?(SupporterNote) - attachment_type = 'SupporterEmail' - elsif item.is_a?(Donation) || item.is_a?(RecurringDonation) || item.is_a?(Refund) || item.is_a?(OffsitePayment) - attachment_type = 'Payment' - end - Activity.where(attachment_type: attachment_type, attachment_id: item.id) + def self.find_activities(item) + attachment_type = item.class.name + if item.is_a?(SupporterNote) + attachment_type = "SupporterEmail" + elsif item.is_a?(Donation) || item.is_a?(RecurringDonation) || item.is_a?(Refund) || item.is_a?(OffsitePayment) + attachment_type = "Payment" end + Activity.where(attachment_type: attachment_type, attachment_id: item.id) + end - def self.revert_reassignments_from_supporter(supporter) - reassignments = Reassignment.where(target_supporter: supporter) - reassignments.each do |reassignment| - reassign_item(reassignment.source_supporter, reassignment.item, reassignment.e_tap_import) - end - reassignments.destroy_all + def self.revert_reassignments_from_supporter(supporter) + reassignments = Reassignment.where(target_supporter: supporter) + reassignments.each do |reassignment| + reassign_item(reassignment.source_supporter, reassignment.item, reassignment.e_tap_import) end + reassignments.destroy_all + end - def self.revert_all_reassignments(etap_import) - reassignments = Reassignment.where(e_tap_import: etap_import) - reassignments.each do |reassignment| - reassign_item(reassignment.source_supporter, reassignment.item, reassignment.e_tap_import) - end - reassignments.destroy_all + def self.revert_all_reassignments(etap_import) + reassignments = Reassignment.where(e_tap_import: etap_import) + reassignments.each do |reassignment| + reassign_item(reassignment.source_supporter, reassignment.item, reassignment.e_tap_import) end + reassignments.destroy_all + end end diff --git a/app/legacy_lib/retrieve_active_record_items.rb b/app/legacy_lib/retrieve_active_record_items.rb index a0b172a9e..520cfa072 100644 --- a/app/legacy_lib/retrieve_active_record_items.rb +++ b/app/legacy_lib/retrieve_active_record_items.rb @@ -1,39 +1,43 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module RetrieveActiveRecordItems - def self.retrieve(data, optional= false) - data.map{|k,v| - our_integer = Integer(v) rescue nil + def self.retrieve(data, optional = false) + data.map { |k, v| + our_integer = begin + Integer(v) + rescue + nil + end unless (optional && v.nil?) || (our_integer && our_integer > 0) raise ArgumentError.new("Value '#{v}' for Key '#{k}' is not valid") end unless k.is_a? Class - raise ArgumentError.new("Key '#{k.to_s}' is not a class") + raise ArgumentError.new("Key '#{k}' is not a class") end ret = [] if optional && v.nil? ret = [k, nil] else - ret = [k, k.where('id = ?', our_integer).first] - if (ret[1] == nil) - raise ParamValidation::ValidationError.new("ID #{v} is not a valid #{k.to_s}", {key: k}) + ret = [k, k.where("id = ?", our_integer).first] + if ret[1].nil? + raise ParamValidation::ValidationError.new("ID #{v} is not a valid #{k}", {key: k}) end end ret }.to_h end - def self.retrieve_from_keys(input, class_to_key_hash, optional=false) - class_to_key_hash.map{|k,v| + def self.retrieve_from_keys(input, class_to_key_hash, optional = false) + class_to_key_hash.map { |k, v| unless k.is_a? Class - raise ArgumentError.new("Key '#{k.to_s}' is not a class") + raise ArgumentError.new("Key '#{k}' is not a class") end ret = nil begin item = retrieve({k => input[v]}, optional) ret = [v, item[k]] rescue ParamValidation::ValidationError - raise ParamValidation::ValidationError.new("ID #{input[v]} is not a valid #{k.to_s}", {key: v}) + raise ParamValidation::ValidationError.new("ID #{input[v]} is not a valid #{k}", {key: v}) rescue ArgumentError raise ParamValidation::ValidationError.new("#{input[v]} is not a valid ID for Key '#{v}'", {key: v}) rescue @@ -42,4 +46,4 @@ def self.retrieve_from_keys(input, class_to_key_hash, optional=false) ret }.to_h end -end \ No newline at end of file +end diff --git a/app/legacy_lib/scheduled_jobs.rb b/app/legacy_lib/scheduled_jobs.rb index 6c7e0a5d6..eeb057899 100644 --- a/app/legacy_lib/scheduled_jobs.rb +++ b/app/legacy_lib/scheduled_jobs.rb @@ -1,9 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' -require 'enumerator' +require "qx" module ScheduledJobs - # Each of these functions should return an Enumerator # Each value in the enumerator should be a lambda # That way the heroku_scheduled_job task can iterate over each lambda @@ -25,13 +23,13 @@ def self.delete_junk_data }) # Delete orphaned tag joins del_tags_orphaned = Qx.delete_from(:tag_joins).where("id IN ($ids)", { - ids: Qx.select("tag_joins.id") - .from(:tag_joins) - .left_join(:supporters, "tag_joins.supporter_id=supporters.id") - .where("supporters.id IS NULL") + ids: Qx.select("tag_joins.id") + .from(:tag_joins) + .left_join(:supporters, "tag_joins.supporter_id=supporters.id") + .where("supporters.id IS NULL") }) - return Enumerator.new do |yielder| + Enumerator.new do |yielder| yielder << lambda do del_cfjs_noval.execute "Successfully cleaned up custom field joins with no values" @@ -47,9 +45,8 @@ def self.delete_junk_data end end - def self.pay_recurring_donations - return Enumerator.new do |yielder| + Enumerator.new do |yielder| yielder << lambda do ids = PayRecurringDonation.pay_all_due_with_stripe "Queued jobs to pay #{ids.count} total recurring donations\n Recurring Donation Ids to run are: \n#{ids.join('\n')}" @@ -74,7 +71,7 @@ def self.update_verification_statuses end def self.update_np_balances - return Enumerator.new do |yielder| + Enumerator.new do |yielder| nps = Nonprofit.where("id IN (?)", Charge.pending.uniq.pluck(:nonprofit_id)) nps.each do |np| yielder << lambda do @@ -86,10 +83,9 @@ def self.update_np_balances end def self.update_pending_payouts - return Enumerator.new do |yielder| + Enumerator.new do |yielder| Payout.pending.includes(:nonprofit).each do |p| yielder << lambda do - err = false if p.transfer_type == :transfer p.status = Stripe::Transfer.retrieve(p.stripe_transfer_id, { stripe_account: p.nonprofit.stripe_account_id @@ -99,7 +95,7 @@ def self.update_pending_payouts stripe_account: p.nonprofit.stripe_account_id }).status end - + p.save "Updated status for NP #{p.nonprofit.id}, payout # #{p.id}" end @@ -108,7 +104,7 @@ def self.update_pending_payouts end def self.delete_expired_source_tokens - return Enumerator.new do |yielder| + Enumerator.new do |yielder| yielder << lambda do tokens_deleted = SourceToken.where("expiration > ?", DateTime.now - 1.day).delete_all "Deleted #{tokens_deleted} source tokens" @@ -117,7 +113,7 @@ def self.delete_expired_source_tokens end def self.send_monthly_reports - return Enumerator.new do |yielder| + Enumerator.new do |yielder| yielder << lambda do if Time.current.day == 1 active_periodic_reports = PeriodicReport.active diff --git a/app/legacy_lib/search_vector.rb b/app/legacy_lib/search_vector.rb index 98033f848..37beb6b39 100644 --- a/app/legacy_lib/search_vector.rb +++ b/app/legacy_lib/search_vector.rb @@ -1,10 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module SearchVector + AcceptedTables = ["supporters", "payments"] - AcceptedTables = ['supporters', 'payments'] - - def self.query(query_string, expr=nil) + def self.query(query_string, expr = nil) query = if (query_string.is_a?(Integer) || query_string.is_int?) && SearchVector.within_postgres_integer_limit(query_string) "(supporters.fts @@ websearch_to_tsquery('english', $search::varchar(255)) OR donations.fts @@ websearch_to_tsquery('english', $search::varchar(255)) @@ -19,17 +18,16 @@ def self.query(query_string, expr=nil) OR ( supporters.phone IS NOT NULL AND supporters.phone != '' - AND supporters.phone_index IS NOT NULL + AND supporters.phone_index IS NOT NULL AND supporters.phone_index != '' AND supporters.phone_index = (regexp_replace($search, '\\D','', 'g')) ) OR donations.fts @@ websearch_to_tsquery('english', $search))" end - (expr || Qexpr.new).where(query, { search: query_string }) + (expr || Qexpr.new).where(query, {search: query_string}) end - def self.within_postgres_integer_limit(test_int) test_int.to_i > 0 && test_int.to_i <= 2147483647 end diff --git a/app/legacy_lib/slug_copy_naming_algorithm.rb b/app/legacy_lib/slug_copy_naming_algorithm.rb index 0407c5ec6..0dfc2f2d5 100644 --- a/app/legacy_lib/slug_copy_naming_algorithm.rb +++ b/app/legacy_lib/slug_copy_naming_algorithm.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SlugCopyNamingAlgorithm < CopyNamingAlgorithm - attr_accessor :klass, :nonprofit_id # @param [Class] klass def initialize(klass, nonprofit_id) - @klass = klass - @nonprofit_id = nonprofit_id + @klass = klass + @nonprofit_id = nonprofit_id end def copy_addition @@ -22,7 +21,6 @@ def get_name_for_entity(name_entity) def get_already_used_name_entities(base_name) end_name = "\\_copy\\_\\d{2}" - @klass.method(:where).call('slug SIMILAR TO ? AND nonprofit_id = ?', base_name + end_name, nonprofit_id).select('slug') + @klass.method(:where).call("slug SIMILAR TO ? AND nonprofit_id = ?", base_name + end_name, nonprofit_id).select("slug") end - -end \ No newline at end of file +end diff --git a/app/legacy_lib/slug_nonprofit_naming_algorithm.rb b/app/legacy_lib/slug_nonprofit_naming_algorithm.rb index 010acc3ca..60eef07cc 100644 --- a/app/legacy_lib/slug_nonprofit_naming_algorithm.rb +++ b/app/legacy_lib/slug_nonprofit_naming_algorithm.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SlugNonprofitNamingAlgorithm < CopyNamingAlgorithm + attr_accessor :state_slug, :city_slug - attr_accessor :state_slug, :city_slug - - def initialize( state_slug, city_slug) - @state_slug = state_slug - @city_slug = city_slug + def initialize(state_slug, city_slug) + @state_slug = state_slug + @city_slug = city_slug end def copy_addition @@ -17,7 +16,7 @@ def max_copies end def separator_before_copy_number - '-' + "-" end def get_name_for_entity(name_entity) @@ -26,7 +25,6 @@ def get_name_for_entity(name_entity) def get_already_used_name_entities(base_name) end_name = "\\-\\d{2}" - Nonprofit.method(:where).call('slug SIMILAR TO ? AND state_code_slug = ? AND city_slug = ?', base_name + end_name, @state_slug, @city_slug).select('slug') + Nonprofit.method(:where).call("slug SIMILAR TO ? AND state_code_slug = ? AND city_slug = ?", base_name + end_name, @state_slug, @city_slug).select("slug") end - -end \ No newline at end of file +end diff --git a/app/legacy_lib/slug_p2p_campaign_naming_algorithm.rb b/app/legacy_lib/slug_p2p_campaign_naming_algorithm.rb index cbbe6aebf..53804df3c 100644 --- a/app/legacy_lib/slug_p2p_campaign_naming_algorithm.rb +++ b/app/legacy_lib/slug_p2p_campaign_naming_algorithm.rb @@ -1,10 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SlugP2pCampaignNamingAlgorithm < CopyNamingAlgorithm - attr_accessor :nonprofit_id # @param [Integer] nonprofit_id def initialize(nonprofit_id) - @nonprofit_id = nonprofit_id + @nonprofit_id = nonprofit_id end def copy_addition @@ -21,7 +20,6 @@ def get_name_for_entity(name_entity) def get_already_used_name_entities(base_name) end_name = "\\_\\d{3}" - Campaign.where('slug SIMILAR TO ? AND nonprofit_id = ?', base_name + end_name, nonprofit_id).select('slug') + Campaign.where("slug SIMILAR TO ? AND nonprofit_id = ?", base_name + end_name, nonprofit_id).select("slug") end - -end \ No newline at end of file +end diff --git a/app/legacy_lib/stripe_account_utils.rb b/app/legacy_lib/stripe_account_utils.rb index 804ab28ff..f74c934a3 100644 --- a/app/legacy_lib/stripe_account_utils.rb +++ b/app/legacy_lib/stripe_account_utils.rb @@ -1,52 +1,51 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module StripeAccountUtils - # Returns the stripe account ID string def self.find_or_create(nonprofit_id) - ParamValidation.new({:nonprofit_id => nonprofit_id}, {:nonprofit_id => {:required=> true, :is_integer => true}}) - begin - np = Nonprofit.find(nonprofit_id) - rescue => e - raise ParamValidation::ValidationError.new("#{nonprofit_id} is not a valid nonprofit", {:key => :nonprofit_id}) - end + ParamValidation.new({nonprofit_id: nonprofit_id}, {nonprofit_id: {required: true, is_integer: true}}) + begin + np = Nonprofit.find(nonprofit_id) + rescue + raise ParamValidation::ValidationError.new("#{nonprofit_id} is not a valid nonprofit", {key: :nonprofit_id}) + end - if !np['stripe_account_id'] - return create(np) + if !np["stripe_account_id"] + create(np) else - return np['stripe_account_id'] + np["stripe_account_id"] end end # np should be a hash with string keys def self.create(np) - ParamValidation.new({:np => np}, {:np => {:required=> true, :is_a => Nonprofit}}) - params = { - type: 'custom', - email: np['email'].present? ? np['email'] : np.roles.nonprofit_admins.order('created_at ASC').first.user.email, - settings: { - payouts: { - schedule: { - interval: 'manual' - } - } - }, - requested_capabilities: [ - 'card_payments', - 'transfers' - ], - business_profile: { - product_description: 'Nonprofit donations' - } - } + ParamValidation.new({np: np}, {np: {required: true, is_a: Nonprofit}}) + params = { + type: "custom", + email: np["email"].presence || np.roles.nonprofit_admins.order("created_at ASC").first.user.email, + settings: { + payouts: { + schedule: { + interval: "manual" + } + } + }, + requested_capabilities: [ + "card_payments", + "transfers" + ], + business_profile: { + product_description: "Nonprofit donations" + } + } - if np['website'] && np['website'] =~ URI::regexp - params[:business_profile][:url] = np['website'] - end - acct = Stripe::Account.create(params, {stripe_version: '2019-09-09' }) - np = Nonprofit.find(np['id']) - np.stripe_account_id = acct.id + if np["website"] && np["website"] =~ URI::DEFAULT_PARSER.make_regexp + params[:business_profile][:url] = np["website"] + end + acct = Stripe::Account.create(params, {stripe_version: "2019-09-09"}) + np = Nonprofit.find(np["id"]) + np.stripe_account_id = acct.id np.save! - return acct.id - end + acct.id + end end diff --git a/app/legacy_lib/stripe_utils.rb b/app/legacy_lib/stripe_utils.rb index 30c1c8175..78b0bd451 100644 --- a/app/legacy_lib/stripe_utils.rb +++ b/app/legacy_lib/stripe_utils.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'stripe' +require "stripe" module StripeUtils - - def self.create_transfer(net_amount, stripe_account_id, currency) - Stripe::Payout.create({ - amount: net_amount, - currency: currency || Settings.intntl.currencies[0] - }, { - stripe_account: stripe_account_id - }) - end + def self.create_transfer(net_amount, stripe_account_id, currency) + Stripe::Payout.create({ + amount: net_amount, + currency: currency || Settings.intntl.currencies[0] + }, { + stripe_account: stripe_account_id + }) + end end diff --git a/app/legacy_lib/supporter_interpolation_dictionary.rb b/app/legacy_lib/supporter_interpolation_dictionary.rb index f8440eafd..2e548b84a 100644 --- a/app/legacy_lib/supporter_interpolation_dictionary.rb +++ b/app/legacy_lib/supporter_interpolation_dictionary.rb @@ -5,10 +5,10 @@ class SupporterInterpolationDictionary < InterpolationDictionary def set_supporter(supporter) if supporter.is_a?(Supporter) && supporter&.name&.present? - add_entry('NAME', supporter&.name&.strip) + add_entry("NAME", supporter&.name&.strip) if supporter.calculated_first_name.present? - add_entry('FIRSTNAME', supporter.calculated_first_name) + add_entry("FIRSTNAME", supporter.calculated_first_name) end end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/temp_block_error.rb b/app/legacy_lib/temp_block_error.rb index 312c02ecf..6499032a4 100644 --- a/app/legacy_lib/temp_block_error.rb +++ b/app/legacy_lib/temp_block_error.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TempBlockError < HoudiniError -end \ No newline at end of file +end diff --git a/app/legacy_lib/timespan.rb b/app/legacy_lib/timespan.rb index 4d93a10f5..3b2a4fdf3 100644 --- a/app/legacy_lib/timespan.rb +++ b/app/legacy_lib/timespan.rb @@ -3,16 +3,14 @@ # Relies on activesupport Timespan = Struct.new(:interval, :time_unit) do - - self::Units = ['week', 'day', 'month', 'year'] + self::Units = ["week", "day", "month", "year"] self::TimeUnits = { - '1_week' => 1.week.ago, - '2_weeks' => 2.weeks.ago, - '1_month' => 1.month.ago, - '3_months' => 3.months.ago, - '6_months' => 6.months.ago, - '1_year' => 1.year.ago, - '2_years' => 2.years.ago + "1_week" => 1.week.ago, + "2_weeks" => 2.weeks.ago, + "1_month" => 1.month.ago, + "3_months" => 3.months.ago, + "6_months" => 6.months.ago, + "1_year" => 1.year.ago, + "2_years" => 2.years.ago } - end diff --git a/app/legacy_lib/to_deprecated_h.rb b/app/legacy_lib/to_deprecated_h.rb index 19073dd87..7371d9e17 100644 --- a/app/legacy_lib/to_deprecated_h.rb +++ b/app/legacy_lib/to_deprecated_h.rb @@ -17,4 +17,4 @@ def to_deprecated_h # unneeded module so zeitwerk:check passes module ToDeprecatedH -end \ No newline at end of file +end diff --git a/app/legacy_lib/update_activities.rb b/app/legacy_lib/update_activities.rb index b76088b4a..ee6813014 100644 --- a/app/legacy_lib/update_activities.rb +++ b/app/legacy_lib/update_activities.rb @@ -1,25 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' +require "qx" module UpdateActivities - def self.for_supporter_notes(note) - - user_email = Qx.select('email') - .from(:users) - .where(id: note[:user_id]) - .execute - .first['email'] + user_email = Qx.select("email") + .from(:users) + .where(id: note[:user_id]) + .execute + .first["email"] Qx.update(:activities) .set(json_data: {content: note[:content], user_email: user_email}.to_json) .timestamps .where(attachment_id: note[:id]) .execute - end - def self.for_one_time_donation(payment) + def self.for_one_time_donation(payment) activity = generate_for_one_time_donation(payment) activity.save! if activity end @@ -30,15 +27,14 @@ def self.generate_for_one_time_donation(payment) if activity activity.date = payment.date json_data = { - 'gross_amount': payment.gross_amount, - 'designation': donation.designation, - 'dedication': donation.dedication + gross_amount: payment.gross_amount, + designation: donation.designation, + dedication: donation.dedication } activity.json_data = json_data return activity end - return nil + nil end end - diff --git a/app/legacy_lib/update_campaign_gift_option.rb b/app/legacy_lib/update_campaign_gift_option.rb index ba52f088c..8a9ee4213 100644 --- a/app/legacy_lib/update_campaign_gift_option.rb +++ b/app/legacy_lib/update_campaign_gift_option.rb @@ -1,10 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateCampaignGiftOption - - def self.update gift_option, params - gift_option.update_attributes params - return gift_option - end - + def self.update gift_option, params + gift_option.update_attributes params + gift_option + end end - diff --git a/app/legacy_lib/update_charges.rb b/app/legacy_lib/update_charges.rb index 0e3c957b4..fe2ea3660 100644 --- a/app/legacy_lib/update_charges.rb +++ b/app/legacy_lib/update_charges.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateCharges + def self.disburse_all_with_payments(payment_ids) + Psql.execute(Qexpr.new.update(:charges, status: "disbursed").where("payment_id IN ($ids)", ids: payment_ids).returning("id", "status")) + end - def self.disburse_all_with_payments(payment_ids) - Psql.execute(Qexpr.new.update(:charges, status: 'disbursed').where("payment_id IN ($ids)", ids: payment_ids).returning('id', 'status')) - end - - def self.reverse_disburse_all_with_payments(payment_ids) - Charge.where("payment_id IN (?)", payment_ids).update_all(status: 'available') - end + def self.reverse_disburse_all_with_payments(payment_ids) + Charge.where("payment_id IN (?)", payment_ids).update_all(status: "available") + end end diff --git a/app/legacy_lib/update_custom_field_joins.rb b/app/legacy_lib/update_custom_field_joins.rb index ef59f0b62..f7baff2f0 100644 --- a/app/legacy_lib/update_custom_field_joins.rb +++ b/app/legacy_lib/update_custom_field_joins.rb @@ -1,23 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' +require "qx" module UpdateCustomFieldJoins - # Delete custom field joins that have the same custom field master # Favor the most recent custom field join def self.delete_dupes(supporter_ids) # Bulk remove duplicate custom field joins, favoring the most recent one - ids = Qx.select('ARRAY_AGG(custom_field_joins.id ORDER BY custom_field_joins.created_at DESC) AS ids') + ids = Qx.select("ARRAY_AGG(custom_field_joins.id ORDER BY custom_field_joins.created_at DESC) AS ids") .from(:custom_field_joins) .where("custom_field_joins.supporter_id IN ($ids)", ids: supporter_ids) .join("custom_field_masters cfms", "cfms.id = custom_field_joins.custom_field_master_id") .group_by("cfms.name") .having("COUNT(custom_field_joins) > 1") - .execute.map{|h| h['ids'][1..-1]}.flatten + .execute.map { |h| h["ids"][1..-1] }.flatten return unless ids.any? Qx.delete_from(:custom_field_joins) .where("id IN ($ids)", ids: ids) .execute end - end diff --git a/app/legacy_lib/update_disputes.rb b/app/legacy_lib/update_disputes.rb index f9b53146f..8840b3ef9 100644 --- a/app/legacy_lib/update_disputes.rb +++ b/app/legacy_lib/update_disputes.rb @@ -1,18 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateDisputes - def self.disburse_all_with_payments(payment_ids) DisputeTransaction.where("payment_id IN (?)", payment_ids).update_all( - disbursed:true, - updated_at:Time.current + disbursed: true, + updated_at: Time.current ) end def self.reverse_disburse_all_with_payments(payment_ids) DisputeTransaction.where("payment_id IN (?)", payment_ids).update_all( - disbursed:false, - updated_at:Time.current + disbursed: false, + updated_at: Time.current ) end end diff --git a/app/legacy_lib/update_donation.rb b/app/legacy_lib/update_donation.rb index 9b431b707..1288642d4 100644 --- a/app/legacy_lib/update_donation.rb +++ b/app/legacy_lib/update_donation.rb @@ -1,36 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateDonation - def self.from_followup(donation, params) donation.designation = params[:designation] if params[:designation].present? donation.dedication = params[:dedication] if params[:dedication].present? donation.comment = params[:comment] if params[:comment].present? donation.save - return donation + donation end # @param [Integer] donation_id the donation for the payment you wish to modify def self.update_payment(donation_id, data) - ParamValidation.new({id:donation_id, data: data}, - { - id: {required: true, is_reference: true}, - data: {required: true, is_hash: true} - }) - existing_payment = Payment.where('donation_id = ?', donation_id).last + ParamValidation.new({id: donation_id, data: data}, + { + id: {required: true, is_reference: true}, + data: {required: true, is_hash: true} + }) + existing_payment = Payment.where("donation_id = ?", donation_id).last unless existing_payment raise ParamValidation::ValidationError.new("#{donation_id} is does not correspond to a valid donation", - {key: :id}) + {key: :id}) end is_offsite = !existing_payment.offsite_payment.nil? validations = { - designation: {is_a: String}, - dedication: {is_a: String}, - comment: {is_a: String}, - campaign_id: {is_reference: true, required:true}, - event_id: {is_reference: true, required: true} + designation: {is_a: String}, + dedication: {is_a: String}, + comment: {is_a: String}, + campaign_id: {is_reference: true, required: true}, + event_id: {is_reference: true, required: true} } if is_offsite @@ -43,13 +42,13 @@ def self.update_payment(donation_id, data) end ParamValidation.new(data, validations) - set_to_nil = {campaign: data[:campaign_id] == '', event: data[:event_id] == ''} + set_to_nil = {campaign: data[:campaign_id] == "", event: data[:event_id] == ""} # validate campaign and event ids if there and if they belong to nonprofit - if (set_to_nil[:campaign]) + if set_to_nil[:campaign] campaign = nil else - campaign = Campaign.where('id = ?', data[:campaign_id]).first + campaign = Campaign.where("id = ?", data[:campaign_id]).first unless campaign raise ParamValidation::ValidationError.new("#{data[:campaign_id]} is not a valid campaign", {key: :campaign_id}) end @@ -58,10 +57,10 @@ def self.update_payment(donation_id, data) end end - if (set_to_nil[:event]) + if set_to_nil[:event] event = nil else - event = Event.where('id = ?', data[:event_id]).first + event = Event.where("id = ?", data[:event_id]).first unless event raise ParamValidation::ValidationError.new("#{data[:event_id]} is not a valid event", {key: :event_id}) end @@ -78,19 +77,18 @@ def self.update_payment(donation_id, data) donation.comment = data[:comment] if data[:comment] donation.dedication = data[:dedication] if data[:dedication] donation.event = event if event - donation.event = nil if data[:event_id] == '' + donation.event = nil if data[:event_id] == "" donation.campaign = campaign if campaign - donation.campaign = nil if data[:campaign_id] == '' + donation.campaign = nil if data[:campaign_id] == "" if is_offsite donation.amount = data[:gross_amount] if data[:gross_amount] donation.date = data[:date] if data[:date] end - # edits_to_payments if is_offsite - #if offline, set date, gross_amount, fee_total, net_amount + # if offline, set date, gross_amount, fee_total, net_amount existing_payment.towards = data[:designation] if data[:designation] existing_payment.date = data[:date] if data[:date] existing_payment.gross_amount = data[:gross_amount] if data[:gross_amount] @@ -101,13 +99,11 @@ def self.update_payment(donation_id, data) something_changed = true existing_payment.save! end - else - if donation.designation - Payment.where('donation_id = ?', donation.id).update_all(:towards => donation.designation, updated_at: Time.now) - end + elsif donation.designation + Payment.where("donation_id = ?", donation.id).update_all(towards: donation.designation, updated_at: Time.now) end - #if offsite, set check_number, date, gross_amount + # if offsite, set check_number, date, gross_amount if is_offsite offsite_payment = existing_payment.offsite_payment offsite_payment.check_number = data[:check_number] if data[:check_number] @@ -147,7 +143,10 @@ def self.update_payment(donation_id, data) # def self.redesignate_donation(donation, new_designation) donation.designation = new_designation - donation.payments.each{|i| i.towards = new_designation; i.save!} + donation.payments.each { |i| + i.towards = new_designation + i.save! + } donation.save! end @@ -159,12 +158,9 @@ def self.correct_donations_when_date_and_payments_are_off(id) donation.date = donation.created_at donation.save! + payments = Payment.where("donation_id = ?", id).includes(:charge) - - payments = Payment.where('donation_id = ?', id).includes(:charge) - - - payments.each {|p| + payments.each { |p| @payments_corrected.push(p.id) p.date = p.charge.created_at p.save! @@ -178,14 +174,23 @@ def self.correct_donations_when_date_and_payments_are_off(id) def self.any_donations_with_created_at_after_date donation_ids = Set.new - CSV.foreach('bad_payments_2.csv').select {|row| true if Integer(row[0]) rescue false}.collect{|row| - is_int = true if Integer(row[0]) rescue false - if (is_int && Float(row[6]) > 0) + CSV.foreach("bad_payments_2.csv").select { |row| + begin + true if Integer(row[0]) + rescue + false + end + }.collect { |row| + begin + is_int = true if Integer(row[0]) + rescue + false + end + if is_int && Float(row[6]) > 0 donation_ids.add(row[0]) end } - return donation_ids + donation_ids end end - diff --git a/app/legacy_lib/update_email_settings.rb b/app/legacy_lib/update_email_settings.rb index 463a5ccaa..521499626 100644 --- a/app/legacy_lib/update_email_settings.rb +++ b/app/legacy_lib/update_email_settings.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateEmailSettings - def self.save(np_id, user_id, params) es = Psql.execute( Qexpr.new.select(:id).from(:email_settings) @@ -8,12 +7,12 @@ def self.save(np_id, user_id, params) .where("user_id=$id", id: user_id) ).first if es.nil? - es = Psql.execute(Qexpr.new.insert('email_settings', [{nonprofit_id: np_id, user_id: user_id}], {no_timestamps: true})).first + es = Psql.execute(Qexpr.new.insert("email_settings", [{nonprofit_id: np_id, user_id: user_id}], {no_timestamps: true})).first end Psql.execute( Qexpr.new.update(:email_settings, params) - .where("id=$id", id: es['id']) - .returning('*') + .where("id=$id", id: es["id"]) + .returning("*") ).first end end diff --git a/app/legacy_lib/update_manual_balance_adjustments.rb b/app/legacy_lib/update_manual_balance_adjustments.rb index b26930d6b..7a28911e4 100644 --- a/app/legacy_lib/update_manual_balance_adjustments.rb +++ b/app/legacy_lib/update_manual_balance_adjustments.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateManualBalanceAdjustments - def self.disburse_all_with_payments(payment_ids) ManualBalanceAdjustment.where("payment_id IN (?)", payment_ids).update_all( - disbursed:true, - updated_at:Time.current + disbursed: true, + updated_at: Time.current ) end end diff --git a/app/legacy_lib/update_miscellaneous_np_info.rb b/app/legacy_lib/update_miscellaneous_np_info.rb index 1dae749df..97e4675ca 100644 --- a/app/legacy_lib/update_miscellaneous_np_info.rb +++ b/app/legacy_lib/update_miscellaneous_np_info.rb @@ -1,29 +1,29 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateMiscellaneousNpInfo def self.update(np_id, misc_settings) - ParamValidation.new({np_id: np_id, misc_settings:misc_settings}, - np_id: {:required => true, :is_integer => true}, - misc_settings: {:required => true, :is_hash => true}) - np = Nonprofit.where('id = ?', np_id).first + ParamValidation.new({np_id: np_id, misc_settings: misc_settings}, + np_id: {required: true, is_integer: true}, + misc_settings: {required: true, is_hash: true}) + np = Nonprofit.where("id = ?", np_id).first raise ParamValidation::ValidationError.new("Nonprofit #{np_id} does not exist", {key: :np_id}) unless np - misc = MiscellaneousNpInfo.where('nonprofit_id = ?', np_id).first + misc = MiscellaneousNpInfo.where("nonprofit_id = ?", np_id).first unless misc misc = MiscellaneousNpInfo.new misc.nonprofit = np end - if (misc_settings[:donate_again_url].present?) + if misc_settings[:donate_again_url].present? misc.donate_again_url = misc_settings[:donate_again_url] end - if (misc_settings[:change_amount_message].present?) - if (Format::HTML.has_only_empty_tags(misc_settings[:change_amount_message])) - misc.change_amount_message= nil; + if misc_settings[:change_amount_message].present? + misc.change_amount_message = if Format::HTML.has_only_empty_tags(misc_settings[:change_amount_message]) + nil else - misc.change_amount_message = misc_settings[:change_amount_message] + misc_settings[:change_amount_message] end end misc.save! misc end -end \ No newline at end of file +end diff --git a/app/legacy_lib/update_nonprofit.rb b/app/legacy_lib/update_nonprofit.rb index 468b3f19c..e68768e07 100644 --- a/app/legacy_lib/update_nonprofit.rb +++ b/app/legacy_lib/update_nonprofit.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateNonprofit - # Update charges from pending to available if the nonprofit's balance on stripe can accommodate them # First, get net balance on Stripe, then get net balance on CC # Take the difference of those two, and mark as many oldest pending charges as 'available' as are less than or equal to that difference def self.mark_available_charges(npo_id) - stripe_account_id = Qx.select("stripe_account_id").from(:nonprofits).where(id: npo_id).ex.first['stripe_account_id'] + stripe_account_id = Qx.select("stripe_account_id").from(:nonprofits).where(id: npo_id).ex.first["stripe_account_id"] stripe_net_balance = Stripe::Balance.retrieve(stripe_account: stripe_account_id).available.first.amount - cc_net_balance = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(npo_id))['net_amount'] + cc_net_balance = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(npo_id))["net_amount"] pending_payments = Qx.select("payments.net_amount", "charges.id AS charge_id") .from(:payments) @@ -22,14 +21,12 @@ def self.mark_available_charges(npo_id) remaining_balance = stripe_net_balance - cc_net_balance charge_ids = pending_payments.take_while do |payment| - if payment['net_amount'] <= remaining_balance - remaining_balance -= payment['net_amount'] + if payment["net_amount"] <= remaining_balance + remaining_balance -= payment["net_amount"] true end - end.map{|h| h['charge_id']} + end.map { |h| h["charge_id"] } - Qx.update(:charges).set(status: 'available').where("id IN ($ids)", ids: charge_ids).execute if charge_ids.any? + Qx.update(:charges).set(status: "available").where("id IN ($ids)", ids: charge_ids).execute if charge_ids.any? end - end - diff --git a/app/legacy_lib/update_order.rb b/app/legacy_lib/update_order.rb index 237388597..aa351d1d8 100644 --- a/app/legacy_lib/update_order.rb +++ b/app/legacy_lib/update_order.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'qx' +require "qx" module UpdateOrder - # data is an array of hashes of: # - id : id of row to update - # - order: new order of row to update + # - order: new order of row to update def self.with_data(table_name, data) - vals = data.map{|h| "(#{h[:id].to_i}, #{h[:order].to_i})"}.join(", ") + vals = data.map { |h| "(#{h[:id].to_i}, #{h[:order].to_i})" }.join(", ") from_str = "(VALUES #{vals}) AS data(id, \"order\")" - return Qx.update("#{table_name}") + Qx.update("#{table_name}") .set('"order"="data"."order"') .timestamps .from(from_str) @@ -17,6 +16,4 @@ def self.with_data(table_name, data) .returning("#{table_name}.order", "#{table_name}.id") .execute end - end - diff --git a/app/legacy_lib/update_payouts.rb b/app/legacy_lib/update_payouts.rb index 3cb8441ff..1827c3001 100644 --- a/app/legacy_lib/update_payouts.rb +++ b/app/legacy_lib/update_payouts.rb @@ -1,22 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdatePayouts - def self.reverse_with_stripe(payout_id, status, failure_message) - ParamValidation.new({payout_id:payout_id, status: status, failure_message: failure_message}, { - payout_id: {required: true, is_integer: true}, - status: {included_in:['pending', 'paid', 'canceled', 'failed'], required: true}, - failure_message: {not_blank: true, required: true} + ParamValidation.new({payout_id: payout_id, status: status, failure_message: failure_message}, { + payout_id: {required: true, is_integer: true}, + status: {included_in: ["pending", "paid", "canceled", "failed"], required: true}, + failure_message: {not_blank: true, required: true} }) - payout = Payout.where('id = ?', payout_id).first + payout = Payout.where("id = ?", payout_id).first unless payout raise ParamValidation::ValidationError.new("No payout with id number: #{payout_id} ", [{key: :payout_id}]) end - payment_ids = payout.payments.select('payments.id').map{|i| i.id}.to_a + payment_ids = payout.payments.select("payments.id").map { |i| i.id }.to_a if payment_ids.count < 1 raise ArgumentError.new("No payments are available to reverse.") end - now = Time.current + Time.current Psql.transaction do # Retrieve all payments with available charges and undisbursed refunds @@ -33,9 +32,8 @@ def self.reverse_with_stripe(payout_id, status, failure_message) payout.failure_message = failure_message payout.save! - - #NonprofitMailer.delay.pending_payout_notification(payout['id'].to_i) + # NonprofitMailer.delay.pending_payout_notification(payout['id'].to_i) payout end end -end \ No newline at end of file +end diff --git a/app/legacy_lib/update_recurring_donations.rb b/app/legacy_lib/update_recurring_donations.rb index 44a5977cd..8593adcb8 100644 --- a/app/legacy_lib/update_recurring_donations.rb +++ b/app/legacy_lib/update_recurring_donations.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateRecurringDonations - class UpdateModel include ActiveModel::Validations attr_accessor :amount - validates :amount, :presence => true, :numericality => {:greater_than_or_equal_to => 0.75} + validates :amount, presence: true, numericality: {greater_than_or_equal_to: 0.75} end # Update the card id and name for a given recurring donation (provide rd['donation_id']) @@ -13,57 +12,55 @@ def self.update_card_id(rd, token) rd = rd&.to_deprecated_h&.with_indifferent_access ParamValidation.new({rd: rd, token: token}, - { - rd: {is_hash: true, required: true}, - token: {format: UUID::Regex, required: true} - }) + { + rd: {is_hash: true, required: true}, + token: {format: UUID::Regex, required: true} + }) ParamValidation.new(rd, - { - id: {is_reference: true, required: true} - }) + { + id: {is_reference: true, required: true} + }) source_token = QuerySourceToken.get_and_increment_source_token(token, nil) tokenizable = source_token.tokenizable - - entities = RetrieveActiveRecordItems.retrieve_from_keys(rd, RecurringDonation => :id ) + entities = RetrieveActiveRecordItems.retrieve_from_keys(rd, RecurringDonation => :id) validate_entities(entities[:id], tokenizable) Qx.transaction do rec_don = entities[:id] donation = rec_don.donation - #TODO This is stupid but the two are used together inconsistently. We should scrap one or the other. + # TODO This is stupid but the two are used together inconsistently. We should scrap one or the other. donation.card = tokenizable rec_don.card_id = tokenizable rec_don.n_failures = 0 rec_don.save! donation.save! - rec_don.supporter.supporter_notes.create!( content: "This supporter updated their card for their recurring donation with ID #{rec_don.id}", user: User.find(540)) + rec_don.supporter.supporter_notes.create!(content: "This supporter updated their card for their recurring donation with ID #{rec_don.id}", user: User.find(540)) end - return QueryRecurringDonations.fetch_for_edit(rd[:id])['recurring_donation'] + QueryRecurringDonations.fetch_for_edit(rd[:id])["recurring_donation"] end # Update the paydate for a given recurring donation (provide rd['id']) def self.update_paydate(rd, paydate) - return ValidationError.new(['Invalid paydate']) unless (1..28).include?(paydate.to_i) - Psql.execute(Qexpr.new.update(:recurring_donations, paydate: paydate).where("id=$id", id: rd['id'])) - rd['paydate'] = paydate - return rd + return ValidationError.new(["Invalid paydate"]) unless (1..28).include?(paydate.to_i) + Psql.execute(Qexpr.new.update(:recurring_donations, paydate: paydate).where("id=$id", id: rd["id"])) + rd["paydate"] = paydate + rd end # @param [RecurringDonation] rd # @param [String] token # @param [Integer] amount # @param [Boolean] fee_covered - def self.update_amount(rd, token, amount, fee_covered=false) + def self.update_amount(rd, token, amount, fee_covered = false) ParamValidation.new({amount: amount, rd: rd, token: token}, - {amount: {is_integer: true, min: 50, required:true}, - rd: {required:true, is_a: RecurringDonation}, - token: {required:true, format: UUID::Regex} - }) + {amount: {is_integer: true, min: 50, required: true}, + rd: {required: true, is_a: RecurringDonation}, + token: {required: true, format: UUID::Regex}}) source_token = QuerySourceToken.get_and_increment_source_token(token, nil) tokenizable = source_token.tokenizable @@ -72,10 +69,10 @@ def self.update_amount(rd, token, amount, fee_covered=false) previous_amount = rd.amount donation = rd.donation Qx.transaction do - #TODO This is stupid but the two are used together inconsistently. We should scrap one or the other. + # TODO This is stupid but the two are used together inconsistently. We should scrap one or the other. rd.card = tokenizable rd.amount = amount - rd.n_failures= 0 + rd.n_failures = 0 donation.card = tokenizable donation.amount = amount rd.save! @@ -85,36 +82,32 @@ def self.update_amount(rd, token, amount, fee_covered=false) misc.save! end JobQueue.queue(JobTypes::NonprofitRecurringDonationChangeAmountJob, rd.id, previous_amount) - JobQueue.queue(JobTypes::DonorRecurringDonationChangeAmountJob,rd.id, previous_amount) + JobQueue.queue(JobTypes::DonorRecurringDonationChangeAmountJob, rd.id, previous_amount) rd end - def self.update_from_start_dates RecurringDonation.inactive.where("start_date >= ?", Date.today).update_all(active: true) end - def self.update_from_end_dates RecurringDonation.active.where("end_date < ?", Date.today).update_all(active: false) end - # Cancel a recurring donation (set active='f') and record the supporter/user email who did it - def self.cancel(rd_id, email, dont_notify_nonprofit=false) + def self.cancel(rd_id, email, dont_notify_nonprofit = false) recurring_donation = RecurringDonation.find(rd_id) recurring_donation.cancel!(email) - rd = QueryRecurringDonations.fetch_for_edit(rd_id)['recurring_donation'] - Supporter.find(rd['supporter_id']).supporter_notes.create!(content: "This supporter's recurring donation for $#{Format::Currency.cents_to_dollars(rd['amount'])} was cancelled by #{rd['cancelled_by']} on #{Format::Date.simple(rd['cancelled_at'])}", user: User.find(540)); - if (!dont_notify_nonprofit) - DonationMailer.delay.nonprofit_recurring_donation_cancellation(rd['donation_id']) + rd = QueryRecurringDonations.fetch_for_edit(rd_id)["recurring_donation"] + Supporter.find(rd["supporter_id"]).supporter_notes.create!(content: "This supporter's recurring donation for $#{Format::Currency.cents_to_dollars(rd["amount"])} was cancelled by #{rd["cancelled_by"]} on #{Format::Date.simple(rd["cancelled_at"])}", user: User.find(540)) + if !dont_notify_nonprofit + DonationMailer.delay.nonprofit_recurring_donation_cancellation(rd["donation_id"]) end - return rd + rd end - def self.update(rd, params) model = UpdateRecurringDonations::UpdateModel.new @@ -124,7 +117,7 @@ def self.update(rd, params) if !model_valid return model end - + params = set_defaults(params) if params[:donation] rd.donation.update_attributes(params[:donation]) @@ -136,13 +129,12 @@ def self.update(rd, params) misc = rd.misc_recurring_donation_info || rd.create_misc_recurring_donation_info misc.fee_covered = fee_covered misc.save! - + params = params.except(:fee_covered) rd.update_attributes(params) - return rd + rd end - def self.set_defaults(params) if params[:donation] && params[:donation][:dollars] params[:donation][:amount] = Format::Currency.dollars_to_cents(params[:donation][:dollars]) @@ -151,25 +143,25 @@ def self.set_defaults(params) end if params[:end_date_str] - if params[:end_date_str].blank? || params[:end_date_str] == 'None' - params[:end_date] = nil + params[:end_date] = if params[:end_date_str].blank? || params[:end_date_str] == "None" + nil else - params[:end_date] = Chronic.parse(params[:end_date_str]) + Chronic.parse(params[:end_date_str]) end params = params.except(:end_date_str) end - return params + params end # @param [RecurringDonation] rd # @param [Card] tokenizable def self.validate_entities(rd, tokenizable) - if (rd.cancelled_at) + if rd.cancelled_at raise ParamValidation::ValidationError.new("Recurring Donation #{rd.id} is already cancelled.", key: :id) end - if (tokenizable.deleted) + if tokenizable.deleted raise ParamValidation::ValidationError.new("Tokenized card #{tokenizable.id} is not valid.", key: :token) end @@ -177,6 +169,4 @@ def self.validate_entities(rd, tokenizable) raise ParamValidation::ValidationError.new("Supporter #{rd.supporter.id} does not own card #{tokenizable.id}", key: :token) end end - end - diff --git a/app/legacy_lib/update_refunds.rb b/app/legacy_lib/update_refunds.rb index c04cf0484..e0668b2c7 100644 --- a/app/legacy_lib/update_refunds.rb +++ b/app/legacy_lib/update_refunds.rb @@ -1,16 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateRefunds - - def self.disburse_all_with_payments(payment_ids) - expr = Qx.update(:refunds) + def self.disburse_all_with_payments(payment_ids) + Qx.update(:refunds) .set(disbursed: true) .timestamps .where("payment_id IN ($ids)", ids: payment_ids) - .returning('*') + .returning("*") .execute - end + end - def self.reverse_disburse_all_with_payments(payment_ids) - Refund.where("payment_id IN (?)", payment_ids).update_all(disbursed:false) - end + def self.reverse_disburse_all_with_payments(payment_ids) + Refund.where("payment_id IN (?)", payment_ids).update_all(disbursed: false) + end end diff --git a/app/legacy_lib/update_supporter.rb b/app/legacy_lib/update_supporter.rb index c74e379d9..3af4bf355 100644 --- a/app/legacy_lib/update_supporter.rb +++ b/app/legacy_lib/update_supporter.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateSupporter - - def self.from_info(supporter, params) - supporter.update_attributes(params) - #GeocodeModel.delay.geocode(supporter) - return supporter - end + def self.from_info(supporter, params) + supporter.update_attributes(params) + # GeocodeModel.delay.geocode(supporter) + supporter + end # Bulk delete, meaning mark all supporters given by a query as deleted='t' def self.bulk_delete(np_id, supporter_ids) @@ -13,12 +12,11 @@ def self.bulk_delete(np_id, supporter_ids) .set(deleted: true) .where("id IN ($ids)", ids: supporter_ids) .and_where("nonprofit_id=$id", id: np_id) - .returning('id') + .returning("id") .execute end def self.general_info(supporter_id, data) - Qx.update(:supporters).set(data).where(id: supporter_id).returning('*').ex.last + Qx.update(:supporters).set(data).where(id: supporter_id).returning("*").ex.last end - end diff --git a/app/legacy_lib/update_supporter_notes.rb b/app/legacy_lib/update_supporter_notes.rb index 67fbf4e9e..85efe749d 100644 --- a/app/legacy_lib/update_supporter_notes.rb +++ b/app/legacy_lib/update_supporter_notes.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateSupporterNotes - def self.update(note) Qx.update(:supporter_notes) .set(content: note[:content], user_id: note[:user_id]) @@ -9,17 +8,15 @@ def self.update(note) .where(id: note[:id]) .execute UpdateActivities.for_supporter_notes(note) - end + end # sets the deleted column to true on supporter_notes (soft delete) - # and then does a hard delete on the associated activity + # and then does a hard delete on the associated activity def self.delete(id) Qx.update(:supporter_notes) .set(deleted: true) .where(id: id) .execute Qx.delete_from(:activities).where(attachment_id: id).execute - end - + end end - diff --git a/app/legacy_lib/update_tickets.rb b/app/legacy_lib/update_tickets.rb index 7f615f190..5ae8e0f01 100644 --- a/app/legacy_lib/update_tickets.rb +++ b/app/legacy_lib/update_tickets.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UpdateTickets - - def self.update(data, current_user=nil) + def self.update(data, current_user = nil) ParamValidation.new(data, { - event_id: {required:true, is_reference: true}, - ticket_id: {required: true, is_reference: true}, - token: {format: UUID::Regex}, - bid_id: {is_integer: true}, - #note: nothing to check? + event_id: {required: true, is_reference: true}, + ticket_id: {required: true, is_reference: true}, + token: {format: UUID::Regex}, + bid_id: {is_integer: true}, + # note: nothing to check? - checked_in: {included_in: ['true', 'false', true, false]} + checked_in: {included_in: ["true", "false", true, false]} }) @@ -60,71 +59,69 @@ def self.delete(event_id, ticket_id) def self.delete_card_for_ticket(event_id, ticket_id) begin - ParamValidation.new({ event_id: event_id, ticket_id: ticket_id }, - event_id: { required: true, is_integer: true }, - ticket_id: { required: true, is_integer: true }) + ParamValidation.new({event_id: event_id, ticket_id: ticket_id}, + event_id: {required: true, is_integer: true}, + ticket_id: {required: true, is_integer: true}) rescue ParamValidation::ValidationError => e - return { json: { error: "Validation error\n #{e.message}", errors: e.data }, status: :unprocessable_entity } + return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity} end begin - ticket = Ticket.where('id = ? and event_id = ?', ticket_id, event_id).limit(1).first! + ticket = Ticket.where("id = ? and event_id = ?", ticket_id, event_id).limit(1).first! ticket.card = nil ticket.source_token = nil ticket.save! - return { json: {}, status: :ok } + {json: {}, status: :ok} rescue ActiveRecord::RecordNotFound => e # there's no stinking ticket by that event and ticket - return { json: { error: "No ticket with id #{ticket_id} at event with id #{event_id}\n #{e.message}" }, - status: :unprocessable_entity } + {json: {error: "No ticket with id #{ticket_id} at event with id #{event_id}\n #{e.message}"}, + status: :unprocessable_entity} rescue ActiveRecord::ActiveRecordError - return { json: { error: "There was a DB error. Please contact support" }, - status: :unprocessable_entity } + {json: {error: "There was a DB error. Please contact support"}, + status: :unprocessable_entity} end end def self.validate_entities(entities) - if (entities[:ticket_id].deleted) + if entities[:ticket_id].deleted raise ParamValidation::ValidationError.new("Ticket ID #{entities[:ticket_id].id} is deleted", key: :ticket_id) end - if (entities[:event_id].deleted) + if entities[:event_id].deleted raise ParamValidation::ValidationError.new("Event ID #{entities[:event_id].id} is deleted", key: :event_id) end - if (entities[:ticket_id].event != entities[:event_id]) + if entities[:ticket_id].event != entities[:event_id] raise ParamValidation::ValidationError.new("Ticket ID #{entities[:ticket_id].id} does not belong to event #{entities[:event_id].id}", key: :ticket_id) end end - def self.discount_ticket(ticket, discount) - if (ticket.class != Ticket) + if ticket.class != Ticket ticket = Ticket.find(ticket) end - if (discount > 1 || discount < 0 ) + if discount > 1 || discount < 0 raise ArgumentError.new("Discount must be between 0 and 1. Value was #{discount}") end - Qx.transaction do + Qx.transaction do payment = ticket.payment - payment.gross_amount = payment.gross_amount * (1-discount) - payment.net_amount = payment.net_amount * (1-discount) + payment.gross_amount = payment.gross_amount * (1 - discount) + payment.net_amount = payment.net_amount * (1 - discount) payment.save! op = payment.offsite_payment - op.gross_amount = op.gross_amount * (1-discount) + op.gross_amount = op.gross_amount * (1 - discount) op.save! - activities = ticket.activities.select{|i| i.action_type == 'created'} + activities = ticket.activities.select { |i| i.action_type == "created" } activities.each do |a| - data = JSON::parse(a.json_data) - data['gross_amount'] = Integer(data['gross_amount'] * (1-discount)) - a.json_data = JSON::generate(data) + data = JSON.parse(a.json_data) + data["gross_amount"] = Integer(data["gross_amount"] * (1 - discount)) + a.json_data = JSON.generate(data) a.save! end end - end end diff --git a/app/legacy_lib/uuid.rb b/app/legacy_lib/uuid.rb index 4fb82fe5b..da1e2535b 100644 --- a/app/legacy_lib/uuid.rb +++ b/app/legacy_lib/uuid.rb @@ -1,4 +1,4 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module UUID Regex = /\{?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}?/ -end \ No newline at end of file +end diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index 3d98c82b0..5448b8324 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class AdminMailer < BaseMailer - # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index d3bddc779..41eb2f412 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,4 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ApplicationMailer < BaseMailer - layout 'mailer' + layout "mailer" end diff --git a/app/mailers/base_mailer.rb b/app/mailers/base_mailer.rb index 0ea27508c..faf95c7c0 100644 --- a/app/mailers/base_mailer.rb +++ b/app/mailers/base_mailer.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class BaseMailer < ActionMailer::Base include Devise::Controllers::UrlHelpers - helper ApplicationHelper - default :from => Settings.mailer.default_from, "X-SES-CONFIGURATION-SET" => 'Admin' - layout 'email' + helper ApplicationHelper + default :from => Settings.mailer.default_from, "X-SES-CONFIGURATION-SET" => "Admin" + layout "email" end diff --git a/app/mailers/billing_subscription_mailer.rb b/app/mailers/billing_subscription_mailer.rb index 932407435..9d96b9442 100644 --- a/app/mailers/billing_subscription_mailer.rb +++ b/app/mailers/billing_subscription_mailer.rb @@ -1,13 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class BillingSubscriptionMailer < BaseMailer - def failed_notice(np_id) @nonprofit = Nonprofit.find(np_id) @billing_subscription = @nonprofit.billing_subscription @card = @nonprofit.active_card @billing_plan = @billing_subscription.billing_plan - @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id) - mail(to: @emails, subject: "Action Needed, Please Update Your #{Settings.general.name} Account") + @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id) + mail(to: @emails, subject: "Action Needed, Please Update Your #{Settings.general.name} Account") end - end diff --git a/app/mailers/campaign_mailer.rb b/app/mailers/campaign_mailer.rb index 6919bef28..0e0a7a7d3 100644 --- a/app/mailers/campaign_mailer.rb +++ b/app/mailers/campaign_mailer.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignMailer < BaseMailer + def creation_followup(campaign) + @creator_profile = campaign.profile + @campaign = campaign + mail(to: @creator_profile.user.email, subject: "Get your new campaign rolling! (via #{Settings.general.name})") + end - def creation_followup(campaign) - @creator_profile = campaign.profile - @campaign = campaign - mail(:to => @creator_profile.user.email, :subject => "Get your new campaign rolling! (via #{Settings.general.name})") - end - - def federated_creation_followup(campaign) - @creator_profile = campaign.profile - @campaign = campaign - mail(:to => @creator_profile.user.email, :subject => "Get your new campaign rolling! (via #{Settings.general.name})") - end + def federated_creation_followup(campaign) + @creator_profile = campaign.profile + @campaign = campaign + mail(to: @creator_profile.user.email, subject: "Get your new campaign rolling! (via #{Settings.general.name})") + end end diff --git a/app/mailers/dispute_mailer.rb b/app/mailers/dispute_mailer.rb index 44e9671c9..acf2ed2eb 100644 --- a/app/mailers/dispute_mailer.rb +++ b/app/mailers/dispute_mailer.rb @@ -1,6 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class DisputeMailer < BaseMailer - include ActionView::Helpers::NumberHelper + include ActionView::Helpers::NumberHelper default from: "support@commitchange.com", to: "support@commitchange.com" # Subject can be set in your I18n file at config/locales/en.yml @@ -8,18 +8,17 @@ class DisputeMailer < BaseMailer # # en.dispute_mailer.created.subject # - + def created(dispute) @dispute = dispute @nonprofit = dispute.nonprofit @payment = dispute.original_payment @stripe_dispute = dispute.stripe_dispute - mail subject: t('dispute_mailer.created.subject', + mail subject: t("dispute_mailer.created.subject", dispute_id: @stripe_dispute.stripe_dispute_id, nonprofit_name: @nonprofit.name, - evidence_due_date: @stripe_dispute.evidence_due_date - ) + evidence_due_date: @stripe_dispute.evidence_due_date) end # Subject can be set in your I18n file at config/locales/en.yml @@ -34,12 +33,11 @@ def funds_withdrawn(dispute) @stripe_dispute = dispute.stripe_dispute @withdrawal_transaction = dispute.dispute_transactions.first - mail subject: t('dispute_mailer.funds_withdrawn.subject', + mail subject: t("dispute_mailer.funds_withdrawn.subject", dispute_id: @stripe_dispute.stripe_dispute_id, nonprofit_name: @nonprofit.name, - amount: print_currency(@withdrawal_transaction.payment.net_amount, "$") , - evidence_due_date: @stripe_dispute.evidence_due_date - ) + amount: print_currency(@withdrawal_transaction.payment.net_amount, "$"), + evidence_due_date: @stripe_dispute.evidence_due_date) end # Subject can be set in your I18n file at config/locales/en.yml @@ -54,11 +52,10 @@ def funds_reinstated(dispute) @stripe_dispute = dispute.stripe_dispute @reinstated_transaction = dispute.dispute_transactions.second - mail subject: t('dispute_mailer.funds_reinstated.subject', + mail subject: t("dispute_mailer.funds_reinstated.subject", dispute_id: @stripe_dispute.stripe_dispute_id, nonprofit_name: @nonprofit.name, - amount: print_currency(@reinstated_transaction.payment.net_amount, "$"), - ) + amount: print_currency(@reinstated_transaction.payment.net_amount, "$")) end # Subject can be set in your I18n file at config/locales/en.yml @@ -72,12 +69,12 @@ def won(dispute) @payment = dispute.original_payment @stripe_dispute = dispute.stripe_dispute - mail subject: t('dispute_mailer.won.subject', + mail subject: t("dispute_mailer.won.subject", dispute_id: @stripe_dispute.stripe_dispute_id, - nonprofit_name: @nonprofit.name - ) + nonprofit_name: @nonprofit.name) end - # Subject can be set in your I18n file at config/locales/en.yml + + # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # # en.dispute_mailer.lost.subject @@ -88,10 +85,9 @@ def lost(dispute) @payment = dispute.original_payment @stripe_dispute = dispute.stripe_dispute - mail subject: t('dispute_mailer.lost.subject', + mail subject: t("dispute_mailer.lost.subject", dispute_id: @stripe_dispute.stripe_dispute_id, - nonprofit_name: @nonprofit.name - ) + nonprofit_name: @nonprofit.name) end # Subject can be set in your I18n file at config/locales/en.yml @@ -105,22 +101,19 @@ def updated(dispute) @payment = dispute.original_payment @stripe_dispute = dispute.stripe_dispute - mail subject: t('dispute_mailer.updated.subject', + mail subject: t("dispute_mailer.updated.subject", dispute_id: @stripe_dispute.stripe_dispute_id, nonprofit_name: @nonprofit.name, - evidence_due_date: @stripe_dispute.evidence_due_date - ) - + evidence_due_date: @stripe_dispute.evidence_due_date) end private ## from application_helper. I don't have time to mess with this. - def print_currency(cents, unit="EUR", sign=true) - - dollars = cents.to_f / 100.0 - dollars = number_to_currency(dollars, :unit => "#{unit}", :precision => (dollars.round == dollars) ? 0 : 2) - dollars = dollars[1..-1] if !sign - dollars - end + def print_currency(cents, unit = "EUR", sign = true) + dollars = cents.to_f / 100.0 + dollars = number_to_currency(dollars, unit: "#{unit}", precision: (dollars.round == dollars) ? 0 : 2) + dollars = dollars[1..-1] if !sign + dollars + end end diff --git a/app/mailers/donation_mailer.rb b/app/mailers/donation_mailer.rb index 8f8c83127..ad9e99ddb 100644 --- a/app/mailers/donation_mailer.rb +++ b/app/mailers/donation_mailer.rb @@ -1,142 +1,139 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class DonationMailer < BaseMailer - - # Used for both one-time and recurring donations + # Used for both one-time and recurring donations # can pass in array of admin user_ids to send to only some -- if falsey/empty, will send to all - def donor_payment_notification(donation_id, payment_id, locale=I18n.locale) - @donation = Donation.find(donation_id) - @nonprofit = @donation.nonprofit - @payment = @donation.payments.find(payment_id) + def donor_payment_notification(donation_id, payment_id, locale = I18n.locale) + @donation = Donation.find(donation_id) + @nonprofit = @donation.nonprofit + @payment = @donation.payments.find(payment_id) - interpolation_dict.set_supporter(@donation.supporter) - if @donation.campaign && interpolation_dict.interpolate(@donation.campaign.receipt_message).present? - @thank_you_note = interpolation_dict.interpolate(@donation.campaign.receipt_message) + interpolation_dict.set_supporter(@donation.supporter) + @thank_you_note = if @donation.campaign && interpolation_dict.interpolate(@donation.campaign.receipt_message).present? + interpolation_dict.interpolate(@donation.campaign.receipt_message) else - @thank_you_note = interpolation_dict.interpolate(@nonprofit.thank_you_note) + interpolation_dict.interpolate(@nonprofit.thank_you_note) end @charge = @payment.charge - @reply_to = @nonprofit.email.blank? ? @nonprofit.users.first.email : @nonprofit.email + @reply_to = @nonprofit.email.presence || @nonprofit.users.first.email from = Format::Name.email_from_np(@nonprofit.name) - I18n.with_locale(locale) do - unless @donation.supporter.email.blank? - mail( - to: @donation.supporter.email, - from: from, - reply_to: @reply_to, - subject: I18n.t('mailer.donations.donor_direct_debit_notification.subject', nonprofit_name: @nonprofit.name)) - end + I18n.with_locale(locale) do + unless @donation.supporter.email.blank? + mail( + to: @donation.supporter.email, + from: from, + reply_to: @reply_to, + subject: I18n.t("mailer.donations.donor_direct_debit_notification.subject", nonprofit_name: @nonprofit.name) + ) + end end end - def donor_direct_debit_notification(donation_id, payment_id, locale=I18n.locale) + def donor_direct_debit_notification(donation_id, payment_id, locale = I18n.locale) @donation = Donation.find(donation_id) - @nonprofit = @donation.nonprofit - - interpolation_dict.set_supporter(@donation.supporter) - - if @donation.campaign && interpolation_dict.interpolate(@donation.campaign.receipt_message).present? - @thank_you_note = interpolation_dict.interpolate(@donation.campaign.receipt_message) + @nonprofit = @donation.nonprofit + + interpolation_dict.set_supporter(@donation.supporter) + + @thank_you_note = if @donation.campaign && interpolation_dict.interpolate(@donation.campaign.receipt_message).present? + interpolation_dict.interpolate(@donation.campaign.receipt_message) else - @thank_you_note = interpolation_dict.interpolate(@nonprofit.thank_you_note) + interpolation_dict.interpolate(@nonprofit.thank_you_note) end - reply_to = @nonprofit.email.blank? ? @nonprofit.users.first.email : @nonprofit.email + reply_to = @nonprofit.email.presence || @nonprofit.users.first.email from = Format::Name.email_from_np(@nonprofit.name) I18n.with_locale(locale) do mail( to: @donation.supporter.email, from: from, reply_to: reply_to, - subject: I18n.t('mailer.donations.donor_direct_debit_notification.subject', nonprofit_name: @nonprofit.name) + subject: I18n.t("mailer.donations.donor_direct_debit_notification.subject", nonprofit_name: @nonprofit.name) ) end end - # Used for both one-time and recurring donations - def nonprofit_payment_notification(donation_id, payment_id, user_id=nil) - @donation = Donation.find(donation_id) - @payment = @donation.payments.find(payment_id) - @charge = @payment.charge - @nonprofit = @donation.nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, @donation.campaign ? 'notify_campaigns' : 'notify_payments') + # Used for both one-time and recurring donations + def nonprofit_payment_notification(donation_id, payment_id, user_id = nil) + @donation = Donation.find(donation_id) + @payment = @donation.payments.find(payment_id) + @charge = @payment.charge + @nonprofit = @donation.nonprofit + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, @donation.campaign ? "notify_campaigns" : "notify_payments") if user_id em = User.find(user_id).email # return unless @emails.include?(em) @emails = [em] - end - if @emails.any? - mail(to: @emails, subject: "Donation receipt for #{@donation.supporter.name || @donation.supporter.email}") - end - end + end + if @emails.any? + mail(to: @emails, subject: "Donation receipt for #{@donation.supporter.name || @donation.supporter.email}") + end + end def nonprofit_failed_recurring_donation(donation_id) - @donation = Donation.find(donation_id) - @nonprofit = @donation.nonprofit - @charge = @donation.charges.last - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, @donation.campaign ? 'notify_campaigns' : 'notify_payments') - if @emails.any? - mail(to: @emails, subject: "Recurring donation payment failure for #{@donation.supporter.name || @donation.supporter.email}") - end + @donation = Donation.find(donation_id) + @nonprofit = @donation.nonprofit + @charge = @donation.charges.last + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, @donation.campaign ? "notify_campaigns" : "notify_payments") + if @emails.any? + mail(to: @emails, subject: "Recurring donation payment failure for #{@donation.supporter.name || @donation.supporter.email}") + end end def donor_failed_recurring_donation(donation_id) - @donation = Donation.find(donation_id) - @nonprofit = @donation.nonprofit - @charge = @donation.charges.last - reply_to = @nonprofit.email.blank? ? @nonprofit.users.first.email : @nonprofit.email + @donation = Donation.find(donation_id) + @nonprofit = @donation.nonprofit + @charge = @donation.charges.last + reply_to = @nonprofit.email.presence || @nonprofit.users.first.email from = Format::Name.email_from_np(@nonprofit.name) - mail(to: @donation.supporter.email, from: from, reply_to: reply_to, subject: "Donation payment failure for #{@nonprofit.name}") + mail(to: @donation.supporter.email, from: from, reply_to: reply_to, subject: "Donation payment failure for #{@nonprofit.name}") end def nonprofit_recurring_donation_cancellation(donation_id) - @donation = Donation.find(donation_id) - @nonprofit = @donation.nonprofit - @charge = @donation.charges.last - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, @donation.campaign ? 'notify_campaigns' : 'notify_payments') - if @emails.any? - mail(to: @emails, subject: "Recurring donation cancelled for #{@donation.supporter.name || @donation.supporter.email}") - end - end + @donation = Donation.find(donation_id) + @nonprofit = @donation.nonprofit + @charge = @donation.charges.last + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, @donation.campaign ? "notify_campaigns" : "notify_payments") + if @emails.any? + mail(to: @emails, subject: "Recurring donation cancelled for #{@donation.supporter.name || @donation.supporter.email}") + end + end - def nonprofit_recurring_donation_change_amount(donation_id, previous_amount=nil) - @donation = RecurringDonation.find(donation_id).donation - @nonprofit = @donation.nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_recurring_donations') - @previous_amount = previous_amount - if @emails.any? - mail(to: @emails, subject:"Recurring donation amount changed for #{@donation.supporter.name || @donation.supporter.email}") - end - end + def nonprofit_recurring_donation_change_amount(donation_id, previous_amount = nil) + @donation = RecurringDonation.find(donation_id).donation + @nonprofit = @donation.nonprofit + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_recurring_donations") + @previous_amount = previous_amount + if @emails.any? + mail(to: @emails, subject: "Recurring donation amount changed for #{@donation.supporter.name || @donation.supporter.email}") + end + end - def donor_recurring_donation_change_amount(donation_id, previous_amount=nil) - @donation = RecurringDonation.find(donation_id).donation - @nonprofit = @donation.nonprofit - reply_to = @nonprofit.email.blank? ? @nonprofit.users.first.email : @nonprofit.email + def donor_recurring_donation_change_amount(donation_id, previous_amount = nil) + @donation = RecurringDonation.find(donation_id).donation + @nonprofit = @donation.nonprofit + reply_to = @nonprofit.email.presence || @nonprofit.users.first.email - interpolation_dict.set_supporter(@donation.supporter) - - if @nonprofit.miscellaneous_np_info && interpolation_dict.interpolate(@nonprofit.miscellaneous_np_info.change_amount_message).present? - @thank_you_note = interpolation_dict.interpolate(@nonprofit.miscellaneous_np_info.change_amount_message) - else - @thank_you_note = nil - end - from = Format::Name.email_from_np(@nonprofit.name) - @previous_amount = previous_amount - mail(to: @donation.supporter.email, from: from, reply_to: reply_to, subject: "Recurring donation amount changed for #{@nonprofit.name}") - end + interpolation_dict.set_supporter(@donation.supporter) - def nonprofit_recurring_donation_change_amount(donation_id, previous_amount=nil) - @donation = RecurringDonation.find(donation_id).donation - @nonprofit = @donation.nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_recurring_donations') - @previous_amount = previous_amount - if @emails.any? - mail(to: @emails, subject:"Recurring donation amount changed for #{@donation.supporter.name || @donation.supporter.email}") - end - end + @thank_you_note = if @nonprofit.miscellaneous_np_info && interpolation_dict.interpolate(@nonprofit.miscellaneous_np_info.change_amount_message).present? + interpolation_dict.interpolate(@nonprofit.miscellaneous_np_info.change_amount_message) + end + from = Format::Name.email_from_np(@nonprofit.name) + @previous_amount = previous_amount + mail(to: @donation.supporter.email, from: from, reply_to: reply_to, subject: "Recurring donation amount changed for #{@nonprofit.name}") + end - def interpolation_dict - @interpolation_dict ||= SupporterInterpolationDictionary.new({'NAME' => 'Supporter', 'FIRSTNAME' => 'Supporter'}) - end + def nonprofit_recurring_donation_change_amount(donation_id, previous_amount = nil) + @donation = RecurringDonation.find(donation_id).donation + @nonprofit = @donation.nonprofit + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_recurring_donations") + @previous_amount = previous_amount + if @emails.any? + mail(to: @emails, subject: "Recurring donation amount changed for #{@donation.supporter.name || @donation.supporter.email}") + end + end + def interpolation_dict + @interpolation_dict ||= SupporterInterpolationDictionary.new({"NAME" => "Supporter", "FIRSTNAME" => "Supporter"}) + end end diff --git a/app/mailers/event_mailer.rb b/app/mailers/event_mailer.rb index 49a32b63f..56574de37 100644 --- a/app/mailers/event_mailer.rb +++ b/app/mailers/event_mailer.rb @@ -1,14 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EventMailer < BaseMailer + helper :application - helper :application - - include Devise::Controllers::UrlHelpers - - def creation_followup(event) - @creator_profile = event.profile - @event = event - mail(:to => @creator_profile.user.email, :subject => "Get your new event rolling on #{Settings.general.name}!") - end + include Devise::Controllers::UrlHelpers + def creation_followup(event) + @creator_profile = event.profile + @event = event + mail(to: @creator_profile.user.email, subject: "Get your new event rolling on #{Settings.general.name}!") + end end diff --git a/app/mailers/export_mailer.rb b/app/mailers/export_mailer.rb index 70f181d1e..25d12ba42 100644 --- a/app/mailers/export_mailer.rb +++ b/app/mailers/export_mailer.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ExportMailer < BaseMailer - # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # @@ -9,48 +8,47 @@ class ExportMailer < BaseMailer def export_payments_completed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your payment export is available!') + mail(to: @export.user.email, subject: "Your payment export is available!") end def export_payments_failed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your payment export has failed') + mail(to: @export.user.email, subject: "Your payment export has failed") end - def export_recurring_donations_completed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your recurring donations export is available!') + mail(to: @export.user.email, subject: "Your recurring donations export is available!") end def export_recurring_donations_failed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your recurring donations export has failed') + mail(to: @export.user.email, subject: "Your recurring donations export has failed") end def export_supporters_completed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your supporters export is available!') + mail(to: @export.user.email, subject: "Your supporters export is available!") end def export_supporters_failed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your supporters export has failed') + mail(to: @export.user.email, subject: "Your supporters export has failed") end def export_supporter_notes_completed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your supporter notes export is available!') + mail(to: @export.user.email, subject: "Your supporter notes export is available!") end def export_supporter_notes_failed_notification(export) @export = export - mail(to: @export.user.email, subject: 'Your supporter notes export has failed.') + mail(to: @export.user.email, subject: "Your supporter notes export has failed.") end def export_failed_recurring_donations_monthly_completed_notification(export) diff --git a/app/mailers/generic_mailer.rb b/app/mailers/generic_mailer.rb index 966c5f9e4..d393ea026 100644 --- a/app/mailers/generic_mailer.rb +++ b/app/mailers/generic_mailer.rb @@ -1,20 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class GenericMailer < BaseMailer - def generic_mail(from_email, from_name, message, subject, to_email, to_name) @from_email = from_email @from_name = from_name @message = message - mail(:to => to_email, :from => "#{from_name} <#{Settings.mailer.email}>", :reply_to => from_email, :subject => "#{subject}") + mail(to: to_email, from: "#{from_name} <#{Settings.mailer.email}>", reply_to: from_email, subject: "#{subject}") end # For sending a system notice to super admins def admin_notice(options) @from_email = Settings.mailer.email - @from_name = 'CC Bot' + @from_name = "CC Bot" @message = options[:body] emails = QueryUsers.super_admin_emails - mail(to: emails, from: "#{@from_name} <#{@from_email}>", reply_to: @from_email, subject: options[:subject], template_name: 'generic_mail') + mail(to: emails, from: "#{@from_name} <#{@from_email}>", reply_to: @from_email, subject: options[:subject], template_name: "generic_mail") end - end diff --git a/app/mailers/import_mailer.rb b/app/mailers/import_mailer.rb index 92a126f1b..a45506d66 100644 --- a/app/mailers/import_mailer.rb +++ b/app/mailers/import_mailer.rb @@ -1,10 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ImportMailer < BaseMailer - - def import_completed_notification(import_id) - @import = Import.find(import_id) - @nonprofit = @import.nonprofit - mail(to: @import.user.email, subject: "Your import is complete!") - end - + def import_completed_notification(import_id) + @import = Import.find(import_id) + @nonprofit = @import.nonprofit + mail(to: @import.user.email, subject: "Your import is complete!") + end end diff --git a/app/mailers/nonprofit_admin_mailer.rb b/app/mailers/nonprofit_admin_mailer.rb index f7cad1bb9..ccec12671 100644 --- a/app/mailers/nonprofit_admin_mailer.rb +++ b/app/mailers/nonprofit_admin_mailer.rb @@ -1,28 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class NonprofitAdminMailer < BaseMailer + def new_invite(role, raw_token) + @user = role.user + @title_with_article = Format::Indefinitize.with_article(role.name.to_s.titleize) + @nonprofit = role.host + @token = raw_token + mail(to: @user.email, subject: "You're now #{@title_with_article} of #{@nonprofit.name} on #{Settings.general.name}. Let's set your password.") + end - def new_invite(role, raw_token) - @user = role.user - @title_with_article = Format::Indefinitize.with_article(role.name.to_s.titleize) - @nonprofit = role.host - @token = raw_token - mail(:to => @user.email, :subject => "You're now #{@title_with_article} of #{@nonprofit.name} on #{Settings.general.name}. Let's set your password.") - end + def existing_invite(role) + @user = role.user + @title_with_article = Format::Indefinitize.with_article(role.name.to_s.titleize) + @nonprofit = role.host + mail(to: @user.email, subject: "You're now #{@title_with_article} of #{@nonprofit.name} on #{Settings.general.name}.") + end - def existing_invite(role) - @user = role.user - @title_with_article = Format::Indefinitize.with_article(role.name.to_s.titleize) - @nonprofit = role.host - mail(:to => @user.email, :subject => "You're now #{@title_with_article} of #{@nonprofit.name} on #{Settings.general.name}.") - end - - def supporter_fundraiser(event_or_campaign) - @fundraiser = event_or_campaign - @kind = event_or_campaign.class.name.downcase || 'event' - @nonprofit = event_or_campaign.nonprofit - @profile = event_or_campaign.profile - recipients = @nonprofit.nonprofit_personnel_emails - mail(to: recipients, subject: "A Supporter has created #{Format::Indefinitize.with_article(@kind.capitalize)} for your Nonprofit!") - end + def supporter_fundraiser(event_or_campaign) + @fundraiser = event_or_campaign + @kind = event_or_campaign.class.name.downcase || "event" + @nonprofit = event_or_campaign.nonprofit + @profile = event_or_campaign.profile + recipients = @nonprofit.nonprofit_personnel_emails + mail(to: recipients, subject: "A Supporter has created #{Format::Indefinitize.with_article(@kind.capitalize)} for your Nonprofit!") + end end - diff --git a/app/mailers/nonprofit_mailer.rb b/app/mailers/nonprofit_mailer.rb index 02548e7cb..e56fc1c93 100644 --- a/app/mailers/nonprofit_mailer.rb +++ b/app/mailers/nonprofit_mailer.rb @@ -1,91 +1,90 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class NonprofitMailer < BaseMailer + def refund_notification(refund_id, user_id = nil) + @refund = Refund.find(refund_id) + @charge = @refund.charge + @nonprofit = @refund.payment.nonprofit + @supporter = @refund.payment.supporter + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payments") + if user_id + em = User.find(user_id).email + return unless @emails.include?(em) + @emails = [em] + end + mail(to: @emails, subject: "A new refund has been made for $#{Format::Currency.cents_to_dollars(@refund.amount)}") + end - def refund_notification(refund_id, user_id=nil) - @refund = Refund.find(refund_id) - @charge = @refund.charge - @nonprofit = @refund.payment.nonprofit - @supporter = @refund.payment.supporter - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payments') - if user_id - em = User.find(user_id).email - return unless @emails.include?(em) - @emails = [em] - end - mail(to: @emails, subject: "A new refund has been made for $#{Format::Currency.cents_to_dollars(@refund.amount)}") - end - - def new_bank_account_notification(ba) - @nonprofit = ba.nonprofit - @bank_account = ba - @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id) - mail(to: @emails, subject: "We need to confirm the new bank account") - end + def new_bank_account_notification(ba) + @nonprofit = ba.nonprofit + @bank_account = ba + @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id) + mail(to: @emails, subject: "We need to confirm the new bank account") + end - def pending_payout_notification(payout_id, emails=nil) - @payout = Payout.find(payout_id) - @nonprofit = @payout.nonprofit - @emails = emails || QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - mail(to: @emails, subject: "Payout of available balance now pending") - end + def pending_payout_notification(payout_id, emails = nil) + @payout = Payout.find(payout_id) + @nonprofit = @payout.nonprofit + @emails = emails || QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + mail(to: @emails, subject: "Payout of available balance now pending") + end - def successful_payout_notification(payout) - @nonprofit = payout.nonprofit - @payout = payout - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - mail(to: @emails, subject: "Payout of available balance succeeded") - end + def successful_payout_notification(payout) + @nonprofit = payout.nonprofit + @payout = payout + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + mail(to: @emails, subject: "Payout of available balance succeeded") + end - def failed_payout_notification(payout) - @nonprofit = payout.nonprofit - @payout = payout - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - mail(to: @emails, subject: "Payout could not be completed") - end + def failed_payout_notification(payout) + @nonprofit = payout.nonprofit + @payout = payout + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + mail(to: @emails, subject: "Payout could not be completed") + end - def failed_recurring_donation(recurring_donation) - @recurring_donation = recurring_donation - @nonprofit = recurring_donation.nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_recurring_donations') - mail(to: @emails, subject: "A recurring donation from one of your supporters had a payment failure.") - end + def failed_recurring_donation(recurring_donation) + @recurring_donation = recurring_donation + @nonprofit = recurring_donation.nonprofit + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_recurring_donations") + mail(to: @emails, subject: "A recurring donation from one of your supporters had a payment failure.") + end - def cancelled_recurring_donation(recurring_donation) - @recurring_donation = recurring_donation - @nonprofit = recurring_donation.nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_recurring_donations') - mail(to: @emails, subject: "A recurring donation from one of your supporters was cancelled.") - end + def cancelled_recurring_donation(recurring_donation) + @recurring_donation = recurring_donation + @nonprofit = recurring_donation.nonprofit + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_recurring_donations") + mail(to: @emails, subject: "A recurring donation from one of your supporters was cancelled.") + end - def verified_notification(nonprofit) - @nonprofit = nonprofit - @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id) - mail(to: @emails, subject: "Your nonprofit has been verified!") - end + def verified_notification(nonprofit) + @nonprofit = nonprofit + @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id) + mail(to: @emails, subject: "Your nonprofit has been verified!") + end - def button_code(nonprofit, to_email, to_name, from_email, message, code) - @nonprofit = nonprofit - @to_email = to_email - @to_name = to_name - @from = from_email - @message = message - @code = code + def button_code(nonprofit, to_email, to_name, from_email, message, code) + @nonprofit = nonprofit + @to_email = to_email + @to_name = to_name + @from = from_email + @message = message + @code = code from = Format::Name.email_from_np(@nonprofit.name) - mail(to: to_email, from: from, reply_to: from_email, subject: "Please include this donate button code on the website") - end + mail(to: to_email, from: from, reply_to: from_email, subject: "Please include this donate button code on the website") + end def invoice_payment_notification(nonprofit_id, payment) @nonprofit = Nonprofit.find(nonprofit_id) @payment = payment @emails = QueryUsers.all_nonprofit_user_emails(@nonprofit.id, [:nonprofit_admin]) @month_name = Date::MONTHNAMES[payment.date.month] - mail(to: @emails, subject: "#{Settings.general.name} Subscription Receipt for #{@month_name}") + mail(to: @emails, subject: "#{Settings.general.name} Subscription Receipt for #{@month_name}") end def first_charge_email(np_id) @nonprofit = Nonprofit.find(np_id) @emails = QueryUsers.all_nonprofit_user_emails(np_id, [:nonprofit_admin]) - mail(to: @emails, reply_to: 'support@commitchange.com', from: "#{Settings.general.name} Support ", subject: "Congratulations on your first charge on #{Settings.general.name}!") + mail(to: @emails, reply_to: "support@commitchange.com", from: "#{Settings.general.name} Support ", subject: "Congratulations on your first charge on #{Settings.general.name}!") end def welcome(np_id) @@ -93,7 +92,6 @@ def welcome(np_id) @user = @nonprofit.users.first @token = @user.make_confirmation_token! @emails = QueryUsers.all_nonprofit_user_emails(np_id, [:nonprofit_admin]) - mail(to: @emails, reply_to: 'support@commitchange.com', from: "#{Settings.general.name} Support ", subject: "A hearty welcome from the #{Settings.general.name} team") + mail(to: @emails, reply_to: "support@commitchange.com", from: "#{Settings.general.name} Support ", subject: "A hearty welcome from the #{Settings.general.name} team") end end - diff --git a/app/mailers/payment_mailer.rb b/app/mailers/payment_mailer.rb index 6f476afff..f621c8791 100644 --- a/app/mailers/payment_mailer.rb +++ b/app/mailers/payment_mailer.rb @@ -1,16 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class PaymentMailer < BaseMailer - # Send a donation receipt to a single admin # or a ticket receipt def resend_admin_receipt(payment_id, user_id) payment = Payment.find(payment_id) - if payment.kind == 'Donation' || payment.kind == 'RecurringDonation' - return JobQueue.queue(JobTypes::NonprofitPaymentNotificationJob, payment.donation.id, payment_id, user_id) - elsif payment.kind == 'Ticket' - return JobQueue.queue(JobTypes::TicketMailerReceiptAdminJob, payment.tickets.pluck(:id), user_id) - elsif payment.kind == 'Refund' - return Delayed::Job.enqueue JobTypes::NonprofitRefundNotificationJob.new(payment.refund.id, user_id) + if payment.kind == "Donation" || payment.kind == "RecurringDonation" + JobQueue.queue(JobTypes::NonprofitPaymentNotificationJob, payment.donation.id, payment_id, user_id) + elsif payment.kind == "Ticket" + JobQueue.queue(JobTypes::TicketMailerReceiptAdminJob, payment.tickets.pluck(:id), user_id) + elsif payment.kind == "Refund" + Delayed::Job.enqueue JobTypes::NonprofitRefundNotificationJob.new(payment.refund.id, user_id) end end @@ -18,13 +17,12 @@ def resend_admin_receipt(payment_id, user_id) # or a ticket followup email to the supporter def resend_donor_receipt(payment_id) payment = Payment.find(payment_id) - if payment.kind == 'Donation' || payment.kind == 'RecurringDonation' - return JobQueue.queue(JobTypes::DonorPaymentNotificationJob, payment.donation.id, payment.id) - elsif payment.kind == 'Ticket' - return TicketMailer.followup(payment.tickets.pluck(:id), payment.charge.id).deliver - elsif payment.kind == 'Refund' - return Delayed::Job.enqueue JobTypes::DonorRefundNotificationJob.new(payment.refund.id) + if payment.kind == "Donation" || payment.kind == "RecurringDonation" + JobQueue.queue(JobTypes::DonorPaymentNotificationJob, payment.donation.id, payment.id) + elsif payment.kind == "Ticket" + TicketMailer.followup(payment.tickets.pluck(:id), payment.charge.id).deliver + elsif payment.kind == "Refund" + Delayed::Job.enqueue JobTypes::DonorRefundNotificationJob.new(payment.refund.id) end end - end diff --git a/app/mailers/recurring_donation_mailer.rb b/app/mailers/recurring_donation_mailer.rb index d1a4a649e..925f3149e 100644 --- a/app/mailers/recurring_donation_mailer.rb +++ b/app/mailers/recurring_donation_mailer.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class RecurringDonationMailer < BaseMailer + def send_cancellation_notices(recurring_donation) + UserMailer.recurring_donation_cancelled(recurring_donation).deliver + NonprofitMailer.cancelled_recurring_donation(recurring_donation).deliver + recurring_donation + end - def send_cancellation_notices(recurring_donation) - UserMailer.recurring_donation_cancelled(recurring_donation).deliver - NonprofitMailer.cancelled_recurring_donation(recurring_donation).deliver - return recurring_donation - end - - def send_failure_notifications(recurring_donation) - UserMailer.recurring_donation_failure(recurring_donation).deliver - NonprofitMailer.failed_recurring_donation(recurring_donation).deliver - end + def send_failure_notifications(recurring_donation) + UserMailer.recurring_donation_failure(recurring_donation).deliver + NonprofitMailer.failed_recurring_donation(recurring_donation).deliver + end end diff --git a/app/mailers/stripe_account_mailer.rb b/app/mailers/stripe_account_mailer.rb index 433827698..22d83b754 100644 --- a/app/mailers/stripe_account_mailer.rb +++ b/app/mailers/stripe_account_mailer.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class StripeAccountMailer < BaseMailer - def verified(nonprofit) @nonprofit = nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - mail(to: @emails, subject: "Verification successful on #{Settings.general.name}!", - template_name: 'verified') + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + mail(to: @emails, subject: "Verification successful on #{Settings.general.name}!", + template_name: "verified") end def conditionally_send_verified(stripe_account) @@ -15,31 +14,31 @@ def conditionally_send_verified(stripe_account) end end - def more_info_needed(nonprofit, deadline=nil) + def more_info_needed(nonprofit, deadline = nil) @nonprofit = nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - @deadline = deadline.in_time_zone(@nonprofit.timezone).strftime('%B%e, %Y at%l:%M:%S %p') if deadline - mail(to: @emails, subject: "Urgent: More Info Needed for Your #{Settings.general.name} Verification", - template_name: 'more_info_needed') + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + @deadline = deadline.in_time_zone(@nonprofit.timezone).strftime("%B%e, %Y at%l:%M:%S %p") if deadline + mail(to: @emails, subject: "Urgent: More Info Needed for Your #{Settings.general.name} Verification", + template_name: "more_info_needed") end - def conditionally_send_more_info_needed(stripe_account, email_to_send_guid, override=false) + def conditionally_send_more_info_needed(stripe_account, email_to_send_guid, override = false) conditionally_send(stripe_account, email_to_send_guid, override) do |stripe_account| - if (stripe_account&.nonprofit) + if stripe_account&.nonprofit more_info_needed(stripe_account.nonprofit).deliver end end end - def not_completed(nonprofit, deadline=nil) + def not_completed(nonprofit, deadline = nil) @nonprofit = nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - @deadline = deadline.in_time_zone(@nonprofit.timezone).strftime('%B%e, %Y at%l:%M:%S %p') if deadline - mail(to: @emails, subject: "Please Complete Your #{Settings.general.name} Account Verification", - template_name: 'not_completed') + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + @deadline = deadline.in_time_zone(@nonprofit.timezone).strftime("%B%e, %Y at%l:%M:%S %p") if deadline + mail(to: @emails, subject: "Please Complete Your #{Settings.general.name} Account Verification", + template_name: "not_completed") end - def conditionally_send_not_completed(stripe_account, email_to_send_guid, override=false) + def conditionally_send_not_completed(stripe_account, email_to_send_guid, override = false) conditionally_send(stripe_account, email_to_send_guid, override) do |stripe_account| if stripe_account&.nonprofit more_info_needed(stripe_account.nonprofit).deliver @@ -47,12 +46,12 @@ def conditionally_send_not_completed(stripe_account, email_to_send_guid, overrid end end - def no_longer_verified(nonprofit, deadline=nil) + def no_longer_verified(nonprofit, deadline = nil) @nonprofit = nonprofit - @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_payouts') - @deadline = deadline.in_time_zone(@nonprofit.timezone).strftime('%B%e, %Y at%l:%M:%S %p') if deadline - mail(to: @emails, subject: "Additional account verification needed for #{Settings.general.name}", - template_name: 'no_longer_verified') + @emails = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_payouts") + @deadline = deadline.in_time_zone(@nonprofit.timezone).strftime("%B%e, %Y at%l:%M:%S %p") if deadline + mail(to: @emails, subject: "Additional account verification needed for #{Settings.general.name}", + template_name: "no_longer_verified") end def conditionally_send_no_longer_verified(stripe_account) @@ -61,21 +60,22 @@ def conditionally_send_no_longer_verified(stripe_account) end end - private - def conditionally_send(stripe_account, email_to_send_guid, override=false, &block) + private + + def conditionally_send(stripe_account, email_to_send_guid, override = false, &block) result = nil - if stripe_account&.nonprofit && - (stripe_account - &.nonprofit_verification_process_status || override) + if stripe_account&.nonprofit && + (stripe_account + &.nonprofit_verification_process_status || override) if override result = block.call(stripe_account) - else + else stripe_account .nonprofit_verification_process_status .with_lock("FOR UPDATE") do - if (stripe_account.nonprofit_verification_process_status - .email_to_send_guid == email_to_send_guid || override) + if stripe_account.nonprofit_verification_process_status + .email_to_send_guid == email_to_send_guid || override result = block.call(stripe_account) end end @@ -84,10 +84,9 @@ def conditionally_send(stripe_account, email_to_send_guid, override=false, &bloc end end - def conditionally_send_on_stripe(stripe_account, &block) + def conditionally_send_on_stripe(stripe_account, &block) if stripe_account&.nonprofit block.call(stripe_account) end end - end diff --git a/app/mailers/tax_mailer.rb b/app/mailers/tax_mailer.rb index 59eee07bc..d339e7a9d 100644 --- a/app/mailers/tax_mailer.rb +++ b/app/mailers/tax_mailer.rb @@ -1,17 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TaxMailer < ApplicationMailer - # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # # en.tax_mailer.annual_receipt.subject # - def annual_receipt(supporter:, year:, nonprofit_text:, donation_payments: [], refund_payments:[], dispute_payments: [], dispute_reversal_payments: []) + def annual_receipt(supporter:, year:, nonprofit_text:, donation_payments: [], refund_payments: [], dispute_payments: [], dispute_reversal_payments: []) @supporter = supporter @nonprofit = supporter.nonprofit @year = year - @total = get_payment_sum(donation_payments, refund_payments, dispute_payments, dispute_reversal_payments) @donation_payments = donation_payments.sort_by(&:date) @refund_payments = refund_payments.sort_by(&:date) @@ -19,7 +17,7 @@ def annual_receipt(supporter:, year:, nonprofit_text:, donation_payments: [], re @dispute_reversal_payments = dispute_reversal_payments.sort_by(&:date) @tax_id = supporter.nonprofit.ein - dict = SupporterInterpolationDictionary.new('NAME'=> 'Supporter', 'FIRSTNAME' => 'Supporter') + dict = SupporterInterpolationDictionary.new("NAME" => "Supporter", "FIRSTNAME" => "Supporter") dict.set_supporter(supporter) @nonprofit_text = dict.interpolate(nonprofit_text) @@ -27,9 +25,9 @@ def annual_receipt(supporter:, year:, nonprofit_text:, donation_payments: [], re mail(to: @supporter.email, subject: "#{@year} Tax Receipt from #{@nonprofit.name}") end - private - def get_payment_sum(*payments) - payments.flatten.sum(&:gross_amount) - end + + def get_payment_sum(*payments) + payments.flatten.sum(&:gross_amount) + end end diff --git a/app/mailers/ticket_mailer.rb b/app/mailers/ticket_mailer.rb index 1f070b96e..f5bb81a34 100644 --- a/app/mailers/ticket_mailer.rb +++ b/app/mailers/ticket_mailer.rb @@ -1,29 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TicketMailer < BaseMailer - helper :application # Pass in ticket_ids, event_id, and supporter - def followup(ticket_ids, charge_id=nil) + def followup(ticket_ids, charge_id = nil) @charge = charge_id ? Charge.find(charge_id) : nil @tickets = Ticket.where("id IN(?)", ticket_ids) @event = @tickets.last.event @supporter = @tickets.last.supporter @nonprofit = @supporter.nonprofit from = Format::Name.email_from_np(@nonprofit.name) - reply_to = @nonprofit.email.blank? ? @nonprofit.users.first.email : @nonprofit.email + reply_to = @nonprofit.email.presence || @nonprofit.users.first.email unless @supporter.email.blank? - mail(from: from, to: @supporter.email, reply_to: reply_to, subject: "Your tickets#{@charge ? ' and receipt ' : ' '}for: #{@event.name}") + mail(from: from, to: @supporter.email, reply_to: reply_to, subject: "Your tickets#{@charge ? " and receipt " : " "}for: #{@event.name}") end end - def receipt_admin(ticket_ids, user_id=nil) + def receipt_admin(ticket_ids, user_id = nil) @tickets = Ticket.where("id IN (?)", ticket_ids) @charge = @tickets.last.charge @supporter = @tickets.last.supporter @event = @tickets.last.event @nonprofit = @event.nonprofit - recipients = QueryUsers.nonprofit_user_emails(@nonprofit.id, 'notify_events') + recipients = QueryUsers.nonprofit_user_emails(@nonprofit.id, "notify_events") if user_id em = User.find(user_id).email recipients = [em] @@ -32,5 +31,4 @@ def receipt_admin(ticket_ids, user_id=nil) mail(to: recipients, subject: "Ticket redeemed for #{@event.name} - #{@supporter.name}") end end - end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index f216cc0ef..729a06ace 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,26 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class UserMailer < BaseMailer - - def refund_receipt(refund_id) - @refund = Refund.find(refund_id) + def refund_receipt(refund_id) + @refund = Refund.find(refund_id) @nonprofit = @refund.payment.nonprofit - @charge = @refund.charge + @charge = @refund.charge @supporter = @refund.payment.supporter - reply_to = @nonprofit.email.blank? ? @nonprofit.users.first.email : @nonprofit.email + reply_to = @nonprofit.email.presence || @nonprofit.users.first.email from = Format::Name.email_from_np(@nonprofit.name) - mail(to: @supporter.email, from: from, reply_to: reply_to, subject: "Your refund receipt for #{@nonprofit.name}") - end - - def recurring_donation_failure(recurring_donation) - @recurring_donation = recurring_donation - mail(:to => @recurring_donation.email, - :subject => ("We couldn't process your recurring donation towards #{@recurring_donation.nonprofit.name}.")) - end + mail(to: @supporter.email, from: from, reply_to: reply_to, subject: "Your refund receipt for #{@nonprofit.name}") + end - def recurring_donation_cancelled(recurring_donation) - @recurring_donation = recurring_donation - mail(:to => @recurring_donation.email, - :subject => ("Your recurring donation towards #{@recurring_donation.nonprofit.name} was successfully cancelled.")) - end + def recurring_donation_failure(recurring_donation) + @recurring_donation = recurring_donation + mail(to: @recurring_donation.email, + subject: "We couldn't process your recurring donation towards #{@recurring_donation.nonprofit.name}.") + end + def recurring_donation_cancelled(recurring_donation) + @recurring_donation = recurring_donation + mail(to: @recurring_donation.email, + subject: "Your recurring donation towards #{@recurring_donation.nonprofit.name} was successfully cancelled.") + end end diff --git a/app/models/activity.rb b/app/models/activity.rb index 4b8b031c7..88c34b554 100644 --- a/app/models/activity.rb +++ b/app/models/activity.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Activity < ApplicationRecord - belongs_to :attachment, :polymorphic => true + belongs_to :attachment, polymorphic: true belongs_to :supporter belongs_to :nonprofit end - diff --git a/app/models/bank_account.rb b/app/models/bank_account.rb index 9f4a6ce0e..2d3f2b5de 100644 --- a/app/models/bank_account.rb +++ b/app/models/bank_account.rb @@ -1,45 +1,42 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class BankAccount < ApplicationRecord - - attr_accessible \ - :name, # str (readable bank name identifier, eg. "Wells Fargo *1234") - :confirmation_token, # str (randomly generated private token for email confirmation) - :account_number, # str (last digits only) - :bank_name, # str - :pending_verification, # bool (whether this bank account is still awaiting email confirmation) - :status, # str - :email, # str (contact email associated with the user who created this bank account) - :deleted, # bool (soft delete flag) - :stripe_bank_account_token, # str - :stripe_bank_account_id, # str - :nonprofit_id, :nonprofit - - #validates :stripe_bank_account_token, presence: true, uniqueness: true - # validates :stripe_bank_account_id, presence: true, uniqueness: true - #validates :nonprofit, presence: true - #validates :email, presence: true, format: {with: Email::Regex} - #validate :nonprofit_must_be_vetted, on: :create - #validate :nonprofit_has_stripe_account - - has_many :payouts - belongs_to :nonprofit - - def nonprofit_must_be_vetted - errors.add(:nonprofit, "must be vetted") unless self.nonprofit && self.nonprofit.vetted - end - - - def nonprofit_has_stripe_account - errors.add(:nonprofit, 'must have a Stripe account id') if !self.nonprofit || self.nonprofit.stripe_account_id.blank? - end - - # Manually cause an instance to become invalid - def invalidate! - @not_valid = true - end - - def allows_payout? - !pending_verification && !deleted - end - + attr_accessible \ + :name, # str (readable bank name identifier, eg. "Wells Fargo *1234") + :confirmation_token, # str (randomly generated private token for email confirmation) + :account_number, # str (last digits only) + :bank_name, # str + :pending_verification, # bool (whether this bank account is still awaiting email confirmation) + :status, # str + :email, # str (contact email associated with the user who created this bank account) + :deleted, # bool (soft delete flag) + :stripe_bank_account_token, # str + :stripe_bank_account_id, # str + :nonprofit_id, :nonprofit + + # validates :stripe_bank_account_token, presence: true, uniqueness: true + # validates :stripe_bank_account_id, presence: true, uniqueness: true + # validates :nonprofit, presence: true + # validates :email, presence: true, format: {with: Email::Regex} + # validate :nonprofit_must_be_vetted, on: :create + # validate :nonprofit_has_stripe_account + + has_many :payouts + belongs_to :nonprofit + + def nonprofit_must_be_vetted + errors.add(:nonprofit, "must be vetted") unless nonprofit && nonprofit.vetted + end + + def nonprofit_has_stripe_account + errors.add(:nonprofit, "must have a Stripe account id") if !nonprofit || nonprofit.stripe_account_id.blank? + end + + # Manually cause an instance to become invalid + def invalidate! + @not_valid = true + end + + def allows_payout? + !pending_verification && !deleted + end end diff --git a/app/models/billing_plan.rb b/app/models/billing_plan.rb index c646cbcf0..13e8de772 100644 --- a/app/models/billing_plan.rb +++ b/app/models/billing_plan.rb @@ -1,44 +1,44 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class BillingPlan < ApplicationRecord - Names = ['Starter', 'Fundraising', 'Supporter Management'] - - attr_accessible \ - :name, #str: readable name - :amount, #int (cents) - :stripe_plan_id, #str (matches plan ID in Stripe) Not needed if it's not a paying subscription - :interval, #str ('monthly', 'annual') - :percentage_fee, # 0.038 - :flat_fee - - has_many :billing_subscriptions - - validates :name, :presence => true - validates :amount, :presence => true - validates :percentage_fee, presence: true - - validates_numericality_of :amount, greater_than_or_equal_to: 0 - validates_numericality_of :percentage_fee, less_than: 1, greater_than_or_equal_to: 0 - - validates_numericality_of :flat_fee, only_integer: true, greater_than_or_equal_to: 0 - - concerning :PathCaching do - class_methods do - def clear_cache(np) - Rails.cache.delete(BillingPlan.create_cache_key(np)) - end - - def find_via_cached_np_id(np) - np = Nonprofit.find_via_cached_id(np.id) unless np.is_a? Nonprofit - key = BillingPlan.create_cache_key(np) - Rails.cache.fetch(key, expires_in: 4.hours) do - np.billing_plan - end - end - - def create_cache_key(np) - np = np.id if np.is_a? Nonprofit - "billing_plan_nonprofit_id_#{np}" - end - end - end + Names = ["Starter", "Fundraising", "Supporter Management"] + + attr_accessible \ + :name, # str: readable name + :amount, # int (cents) + :stripe_plan_id, # str (matches plan ID in Stripe) Not needed if it's not a paying subscription + :interval, # str ('monthly', 'annual') + :percentage_fee, # 0.038 + :flat_fee + + has_many :billing_subscriptions + + validates :name, presence: true + validates :amount, presence: true + validates :percentage_fee, presence: true + + validates :amount, numericality: {greater_than_or_equal_to: 0} + validates :percentage_fee, numericality: {less_than: 1, greater_than_or_equal_to: 0} + + validates :flat_fee, numericality: {only_integer: true, greater_than_or_equal_to: 0} + + concerning :PathCaching do + class_methods do + def clear_cache(np) + Rails.cache.delete(BillingPlan.create_cache_key(np)) + end + + def find_via_cached_np_id(np) + np = Nonprofit.find_via_cached_id(np.id) unless np.is_a? Nonprofit + key = BillingPlan.create_cache_key(np) + Rails.cache.fetch(key, expires_in: 4.hours) do + np.billing_plan + end + end + + def create_cache_key(np) + np = np.id if np.is_a? Nonprofit + "billing_plan_nonprofit_id_#{np}" + end + end + end end diff --git a/app/models/billing_subscription.rb b/app/models/billing_subscription.rb index d3dcb63dd..bc0cf6e00 100644 --- a/app/models/billing_subscription.rb +++ b/app/models/billing_subscription.rb @@ -1,56 +1,54 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class BillingSubscription < ApplicationRecord - - attr_accessible \ - :nonprofit_id, :nonprofit, - :billing_plan_id, :billing_plan, - :stripe_subscription_id, - :status # trialing, active, past_due, canceled, or unpaid - - attr_accessor :stripe_plan_id, :manual - belongs_to :nonprofit - belongs_to :billing_plan - - validates :nonprofit, presence: true - validates :billing_plan, presence: true - - def as_json(options={}) - h = super(options) - h[:plan_name] = self.billing_plan.name - h[:plan_amount] = self.billing_plan.amount / 100 - h - end - - def stripe_subscription - Stripe::Subscription.retrieve(stripe_subscription_id) - end - - concerning :PathCaching do - included do - after_save do - nonprofit.clear_cache - true - end - end - - class_methods do - def clear_cache(np) - Rails.cache.delete(BillingSubscription.create_cache_key(np)) - end - - def find_via_cached_np_id(np) - np = np.id if np.is_a? Nonprofit - key = BillingSubscription.create_cache_key(np) - Rails.cache.fetch(key, expires_in: 4.hours) do - Qx.fetch(:billing_subscriptions, {nonprofit_id: np}).last - end - end - - def create_cache_key(np) - np = np.id if np.is_a? Nonprofit - "billing_subscription_nonprofit_id_#{np}" - end - end - end + attr_accessible \ + :nonprofit_id, :nonprofit, + :billing_plan_id, :billing_plan, + :stripe_subscription_id, + :status # trialing, active, past_due, canceled, or unpaid + + attr_accessor :stripe_plan_id, :manual + belongs_to :nonprofit + belongs_to :billing_plan + + validates :nonprofit, presence: true + validates :billing_plan, presence: true + + def as_json(options = {}) + h = super + h[:plan_name] = billing_plan.name + h[:plan_amount] = billing_plan.amount / 100 + h + end + + def stripe_subscription + Stripe::Subscription.retrieve(stripe_subscription_id) + end + + concerning :PathCaching do + included do + after_save do + nonprofit.clear_cache + true + end + end + + class_methods do + def clear_cache(np) + Rails.cache.delete(BillingSubscription.create_cache_key(np)) + end + + def find_via_cached_np_id(np) + np = np.id if np.is_a? Nonprofit + key = BillingSubscription.create_cache_key(np) + Rails.cache.fetch(key, expires_in: 4.hours) do + Qx.fetch(:billing_subscriptions, {nonprofit_id: np}).last + end + end + + def create_cache_key(np) + np = np.id if np.is_a? Nonprofit + "billing_subscription_nonprofit_id_#{np}" + end + end + end end - diff --git a/app/models/campaign.rb b/app/models/campaign.rb index 18f8c963f..ac230f2cb 100644 --- a/app/models/campaign.rb +++ b/app/models/campaign.rb @@ -1,217 +1,210 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Campaign < ApplicationRecord - - attr_accessible \ - :name, - :tagline, - :slug, # str: url name - :total_supporters, - :goal_amount, - :nonprofit_id, - :profile_id, - :main_image, - :remove_main_image, # for carrierwave - :background_image, - :remove_background_image, #bool carrierwave + attr_accessible \ + :name, + :tagline, + :slug, # str: url name + :total_supporters, + :goal_amount, + :nonprofit_id, + :profile_id, + :main_image, + :remove_main_image, # for carrierwave + :background_image, + :remove_background_image, # bool carrierwave :banner_image, :remove_banner_image, - :published, - :video_url, #str - :vimeo_video_id, - :youtube_video_id, - :summary, - :body, - :goal_amount_dollars, #accessor: translated into goal_amount (cents) - :show_total_raised, # bool - :show_total_count, # bool - :hide_activity_feed, # bool + :published, + :video_url, # str + :vimeo_video_id, + :youtube_video_id, + :summary, + :body, + :goal_amount_dollars, # accessor: translated into goal_amount (cents) + :show_total_raised, # bool + :show_total_count, # bool + :hide_activity_feed, # bool :end_datetime, - :deleted, #bool (soft delete) - :hide_goal, # bool - :hide_thermometer, #bool - :hide_title, # bool + :deleted, # bool (soft delete) + :hide_goal, # bool + :hide_thermometer, # bool + :hide_title, # bool :receipt_message, # text :hide_custom_amounts, # boolean :parent_campaign_id, :reason_for_supporting, :default_reason_for_supporting + validate :end_datetime_cannot_be_in_past, on: :create + validates :profile, presence: true + validates :nonprofit, presence: true + validates :goal_amount, + presence: true, numericality: { + only_integer: true + } + validate :validate_goal_amount + validates :name, + presence: true, + length: {maximum: 60} + validates :slug, uniqueness: {scope: :nonprofit_id, message: "You already have a campaign with that URL."}, presence: true + + validates :starting_point, presence: true, + numericality: {only_integer: true, greater_than_or_equal_to: 0} - validate :end_datetime_cannot_be_in_past, :on => :create - validates :profile, :presence => true - validates :nonprofit, :presence => true - validates :goal_amount, - :presence => true, numericality: { - only_integer: true - } - validate :validate_goal_amount - validates :name, - :presence => true, - :length => {:maximum => 60} - validates :slug, uniqueness: {scope: :nonprofit_id, message: 'You already have a campaign with that URL.'}, presence: true + attr_accessor :goal_amount_dollars - validates :starting_point, :presence => true, - :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 } + attr_accessible :starting_point, # integer, number of donors to start with + :goal_is_in_supporters # boolean, true if you want to measure success based on donors instead of amount + + mount_uploader :main_image, CampaignMainImageUploader + mount_uploader :background_image, CampaignBackgroundImageUploader + mount_uploader :banner_image, CampaignBannerImageUploader + + has_many :donations + ## we already have a recurring_donations relationship but it's broken so we'll create one here just as a workaround + has_many :valid_rds, through: :donations, source: :recurring_donation, class_name: "RecurringDonation" + has_many :charges, through: :donations + has_many :payments, through: :donations, source: :payment + has_many :campaign_gift_options + has_many :campaign_gifts, through: :campaign_gift_options + has_many :supporters, through: :donations + has_many :recurring_donations + has_many :roles, as: :host, dependent: :destroy + has_many :activities, as: :host, dependent: :destroy + belongs_to :profile + belongs_to :nonprofit + has_one :misc_campaign_info, dependent: :destroy + belongs_to :widget_description + + belongs_to :parent_campaign, class_name: "Campaign" + has_many :children_campaigns, class_name: "Campaign", foreign_key: "parent_campaign_id" + + scope :published, -> { where(published: true) } + scope :active, -> { where(published: true).where("end_datetime IS NULL OR end_datetime >= ?", Date.today) } + scope :past, -> { where(published: true).where("end_datetime < ?", Date.today) } + scope :unpublished, -> { where(published: [nil, false]) } + scope :not_deleted, -> { where(deleted: [nil, false]) } + scope :deleted, -> { where(deleted: true) } + scope :not_a_child, -> { where(parent_campaign_id: nil) } + + before_validation do + if goal_amount_dollars.present? + self.goal_amount = (goal_amount_dollars.delete(",").to_f * 100).to_i + end + + unless starting_point + self.starting_point = 0 + end + self + end - attr_accessor :goal_amount_dollars + before_validation(on: :create) do + unless slug + self.slug = Format::Url.convert_to_slug(name) + end + set_defaults + self + end + + before_save do + parse_video_id if video_url && video_url_changed? + self + end + + after_create do + user = profile.user + Role.create(name: :campaign_editor, user_id: user.id, host: self) + if child_campaign? + CampaignMailer.delay.federated_creation_followup(self) + else + CampaignMailer.delay.creation_followup(self) + end + + NonprofitAdminMailer.delay.supporter_fundraiser(self) unless QueryRoles.is_nonprofit_user?(user.id, nonprofit_id) + self + end + + after_update :send_campaign_updated + + def set_defaults + self.total_supporters = 1 + self.published = false if published.nil? + end + + def parse_video_id + if video_url.include? "vimeo" + self.vimeo_video_id = video_url.split("/").last + self.youtube_video_id = nil + elsif video_url.include? "youtube" + match = video_url.match(/\?v=(.+)/) + return if match.nil? + self.youtube_video_id = match[1].split("&").first + self.vimeo_video_id = nil + elsif video_url.include? "youtu.be" + self.youtube_video_id = video_url.split("/").last + self.vimeo_video_id = nil + elsif video_url.blank? + self.vimeo_video_id = nil + self.youtube_video_id = nil + end + self + end + + def total_raised + payments.sum(:gross_amount) + end + + def percentage_funded + goal_amount.nil? ? 0 : total_raised * 100 / goal_amount + end + + def average_donation + donations.any? ? total_raised / donations.count : 0 + end - attr_accessible :starting_point, #integer, number of donors to start with - :goal_is_in_supporters #boolean, true if you want to measure success based on donors instead of amount - - mount_uploader :main_image, CampaignMainImageUploader - mount_uploader :background_image, CampaignBackgroundImageUploader - mount_uploader :banner_image, CampaignBannerImageUploader - - has_many :donations - ## we already have a recurring_donations relationship but it's broken so we'll create one here just as a workaround - has_many :valid_rds, :through => :donations, source: :recurring_donation, class_name: 'RecurringDonation' - has_many :charges, through: :donations - has_many :payments, through: :donations, source: :payment - has_many :campaign_gift_options - has_many :campaign_gifts, through: :campaign_gift_options - has_many :supporters, :through => :donations - has_many :recurring_donations - has_many :roles, as: :host, dependent: :destroy - has_many :activities, as: :host, dependent: :destroy - belongs_to :profile - belongs_to :nonprofit - has_one :misc_campaign_info, dependent: :destroy - belongs_to :widget_description - - belongs_to :parent_campaign, class_name: 'Campaign' - has_many :children_campaigns, class_name: 'Campaign', foreign_key: 'parent_campaign_id' - - scope :published, -> {where(:published => true)} - scope :active, -> {where(:published => true).where("end_datetime IS NULL OR end_datetime >= ?", Date.today)} - scope :past, -> {where(:published => true).where("end_datetime < ?", Date.today)} - scope :unpublished, -> {where(:published => [nil, false])} - scope :not_deleted, -> {where(deleted: [nil, false])} - scope :deleted, -> {where(deleted: true)} - scope :not_a_child, -> {where(parent_campaign_id: nil)} - - before_validation do - if self.goal_amount_dollars.present? - self.goal_amount = (self.goal_amount_dollars.gsub(',','').to_f * 100).to_i - end - - unless (self.starting_point) - self.starting_point = 0 - end - self - end - - before_validation(on: :create) do - unless self.slug - self.slug = Format::Url.convert_to_slug(name) - end - self.set_defaults - self - end - - before_save do - self.parse_video_id if self.video_url && self.video_url_changed? - self - end - - after_create do - user = self.profile.user - Role.create(name: :campaign_editor, user_id: user.id, host: self) - if child_campaign? - CampaignMailer.delay.federated_creation_followup(self) - else - CampaignMailer.delay.creation_followup(self) - end - - NonprofitAdminMailer.delay.supporter_fundraiser(self) unless QueryRoles.is_nonprofit_user?(user.id, self.nonprofit_id) - self - end - - after_update :send_campaign_updated - - def set_defaults - - self.total_supporters = 1 - self.published = false if self.published.nil? - end - - - def parse_video_id - if self.video_url.include? 'vimeo' - self.vimeo_video_id = self.video_url.split('/').last - self.youtube_video_id = nil - elsif self.video_url.include? 'youtube' - match = self.video_url.match(/\?v=(.+)/) - return if match.nil? - self.youtube_video_id = match[1].split('&').first - self.vimeo_video_id = nil - elsif self.video_url.include? 'youtu.be' - self.youtube_video_id = self.video_url.split('/').last - self.vimeo_video_id = nil - elsif self.video_url.blank? - self.vimeo_video_id = nil - self.youtube_video_id = nil - end - self - end - - def total_raised - self.payments.sum(:gross_amount) - end - - def percentage_funded - self.goal_amount.nil? ? 0 : self.total_raised * 100 / self.goal_amount - end - - def average_donation - self.donations.any? ? self.total_raised / self.donations.count : 0 - end - - # Validations + # Validations def end_datetime_cannot_be_in_past - if self.end_datetime.present? && self.end_datetime < Time.now + if end_datetime.present? && end_datetime < Time.now errors.add(:end_datetime, "can't be in the past") - end - end - - def ready_to_publish? - [(self.body && self.body.length >= 500), (self.campaign_gift_options.count >= 1)].all? - end - - def url - "#{self.nonprofit.url}/campaigns/#{self.slug}" - end - - def days_left - return 0 if self.end_datetime.nil? - (self.end_datetime.to_date - Date.today).to_i - end - - def finished? - self.end_datetime && self.end_datetime < Time.now - end - - def validate_goal_amount - - goal_amount = self.goal_amount || 0 - if (self.goal_is_in_supporters) - if (goal_amount < 1) - errors.add(:goal_amount, "must be greater than or equal to 1") - end - else - if (goal_amount < 99) - errors.add(:goal_amount, "must be greater than or equal to 99 cents") - end - end - end + end + end + + def ready_to_publish? + [body && body.length >= 500, (campaign_gift_options.count >= 1)].all? + end + + def url + "#{nonprofit.url}/campaigns/#{slug}" + end + + def days_left + return 0 if end_datetime.nil? + (end_datetime.to_date - Date.today).to_i + end + + def finished? + end_datetime && end_datetime < Time.now + end + + def validate_goal_amount + goal_amount = self.goal_amount || 0 + if goal_is_in_supporters + if goal_amount < 1 + errors.add(:goal_amount, "must be greater than or equal to 1") + end + elsif goal_amount < 99 + errors.add(:goal_amount, "must be greater than or equal to 99 cents") + end + end def child_params - excluded_for_peer_to_peer = %w( - id created_at updated_at slug profile_id url + excluded_for_peer_to_peer = %w[ + id created_at updated_at slug profile_id url total_raised show_recurring_amount external_identifier parent_campaign_id reason_for_supporting metadata goal_is_in_supporters - widget_description_id - ) + widget_description_id + ] attributes.except(*excluded_for_peer_to_peer) end @@ -223,52 +216,54 @@ def parent_campaign? !child_campaign? end - def params_to_copy_from_parent - params = %w( - tagline body video_url receipt_message youtube_video_id summary name - ) - - parent_campaign.attributes.slice(*params) - end - - def update_from_parent! - if child_campaign? - params_to_copy_from_parent.each do |k,v| - update_attribute(k, v) - end - [:main_image, :background_image, :banner_image].each do |i| - if parent_campaign.send("#{i.to_s}?") - update_attribute(i, parent_campaign.send(i)) unless !parent_campaign.send(i.to_s) rescue Aws::S3::Errors::NoSuchKey - else - self.send("remove_#{i.to_s}!") - end - end - save! - end - end + def params_to_copy_from_parent + params = %w[ + tagline body video_url receipt_message youtube_video_id summary name + ] + + parent_campaign.attributes.slice(*params) + end + + def update_from_parent! + if child_campaign? + params_to_copy_from_parent.each do |k, v| + update_attribute(k, v) + end + [:main_image, :background_image, :banner_image].each do |i| + if parent_campaign.send("#{i}?") + begin + update_attribute(i, parent_campaign.send(i)) unless !parent_campaign.send(i.to_s) + rescue + Aws::S3::Errors::NoSuchKey + end + else + send("remove_#{i}!") + end + end + save! + end + end def self.get_campaign_and_children(campaign) - where('campaigns.id = ? OR campaigns.parent_campaign_id = ? ',campaign, campaign) + where("campaigns.id = ? OR campaigns.parent_campaign_id = ? ", campaign, campaign) end - def hide_cover_fees? - nonprofit.hide_cover_fees? || misc_campaign_info&.hide_cover_fees_option - end + def hide_cover_fees? + nonprofit.hide_cover_fees? || misc_campaign_info&.hide_cover_fees_option + end - def fee_coverage_option + def fee_coverage_option @fee_coverage_option ||= misc_campaign_info&.fee_coverage_option_config || nonprofit.fee_coverage_option end # generally, don't use - def fee_coverage_option=(option) - @fee_coverage_option = option - end + attr_writer :fee_coverage_option - def paused? - !!(misc_campaign_info&.paused) - end + def paused? + !!misc_campaign_info&.paused + end - def send_campaign_updated - JobQueue.queue(JobTypes::CampaignUpdatedJob, self.id) - end + def send_campaign_updated + JobQueue.queue(JobTypes::CampaignUpdatedJob, id) + end end diff --git a/app/models/campaign_gift.rb b/app/models/campaign_gift.rb index 273cf9f27..0e3e36ac5 100644 --- a/app/models/campaign_gift.rb +++ b/app/models/campaign_gift.rb @@ -1,16 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignGift < ApplicationRecord + attr_accessible \ + :donation_id, + :donation, + :campaign_gift_option, + :campaign_gift_option_id - attr_accessible \ - :donation_id, - :donation, - :campaign_gift_option, - :campaign_gift_option_id - - belongs_to :donation - belongs_to :campaign_gift_option - - validates :donation, presence: true - validates :campaign_gift_option, presence: true + belongs_to :donation + belongs_to :campaign_gift_option + validates :donation, presence: true + validates :campaign_gift_option, presence: true end diff --git a/app/models/campaign_gift_option.rb b/app/models/campaign_gift_option.rb index 673fe615e..30df8b998 100644 --- a/app/models/campaign_gift_option.rb +++ b/app/models/campaign_gift_option.rb @@ -1,39 +1,37 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignGiftOption < ApplicationRecord + attr_accessible \ + :amount_one_time, # int (cents) + :amount_recurring, # int (cents) + :amount_dollars, # str, gets converted to amount + :description, # text + :name, # str + :campaign, # assocation + :quantity, # int (optional) + :to_ship, # boolean + :order, # int (optional) + :hide_contributions # boolean (optional) - attr_accessible \ - :amount_one_time, #int (cents) - :amount_recurring, #int (cents) - :amount_dollars, #str, gets converted to amount - :description, # text - :name, # str - :campaign, #assocation - :quantity, #int (optional) - :to_ship, #boolean - :order, #int (optional) - :hide_contributions #boolean (optional) + belongs_to :campaign, optional: false + has_many :campaign_gifts + has_many :donations, through: :campaign_gifts + has_one :nonprofit, through: :campaign - belongs_to :campaign, required: true - has_many :campaign_gifts - has_many :donations, through: :campaign_gifts - has_one :nonprofit, through: :campaign + validates :name, presence: true + validates :amount_one_time, presence: true, numericality: {only_integer: true}, unless: :amount_recurring + validates :amount_recurring, presence: true, numericality: {only_integer: true}, unless: :amount_one_time - validates :name, presence: true - validates :amount_one_time, presence: true, numericality: { only_integer: true }, unless: :amount_recurring - validates :amount_recurring, presence: true, numericality: { only_integer: true }, unless: :amount_one_time + def total_gifts + campaign_gifts.count + end - def total_gifts - return self.campaign_gifts.count - end - - def gifts_available? - quantity.nil? || quantity.zero? || total_gifts < quantity - end - - def as_json(options={}) - h = super(options) - h[:total_gifts] = self.total_gifts - h - end + def gifts_available? + quantity.nil? || quantity.zero? || total_gifts < quantity + end + def as_json(options = {}) + h = super + h[:total_gifts] = total_gifts + h + end end diff --git a/app/models/card.rb b/app/models/card.rb index a5894c938..b0d33c2a2 100755 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -1,94 +1,87 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Card < ApplicationRecord - - attr_accessible \ - :cardholders_name, # str (name associated with this card) - :email, # str (cache the email associated with this card) - :name, # str (readable card name, eg. Visa *1234) - :failure_message, # accessor for temporarily storing the stripe decline message - :status, # str - :stripe_card_token, # str - :stripe_card_id, # str - :stripe_customer_id, # str - :holder, :holder_id, :holder_type, # polymorphic cardholder association - :inactive # a card is inactive. This is currently only meaningful for nonprofit cards - - scope :amex_only, -> { where('cards.name ILIKE ? OR cards.name ILIKE ?', 'American Express%', 'amex%') } - scope :not_amex, -> { where('cards.name NOT ILIKE ? AND cards.name NOT ILIKE ?', 'American Express%', 'amex%') } - - scope :held_by_nonprofits, -> { where('cards.holder_type = ? ', 'Nonprofit') } - scope :held_by_supporters, -> { where('cards.holder_type = ? ', 'Supporter') } - - attr_accessor :failure_message - - - belongs_to :holder, polymorphic: true - has_many :charges - has_many :donations - has_many :recurring_donations, through: :donations - has_many :tickets - has_one :source_token, as: :tokenizable - - - # an helpful method for getting the supporter when it's the holder - def supporter - if holder_type == 'Supporter' - holder - else - nil - end - end - - # an helpful method for getting the supporter's nonprofit - # when the supporter is the holder - def supporter_nonprofit - supporter&.nonprofit - end - - def amex? - !!(name =~ /American Express.*/i) - end - - def not_amex? - !amex? - end - - def stripe_customer - @stripe_customer ||= Stripe::Customer.retrieve(stripe_customer_id) - end - - def stripe_card - @stripe_card ||= stripe_customer.sources.retrieve(stripe_card_id) - end - - - concerning :Maintenance do - included do - # is this originally from balanced? - scope :legacy_balanced, -> {where('cards.stripe_customer_id ILIKE ?', '%balanced%')} - # Is this originally not from balanced - scope :not_legacy_balanced, -> {where('cards.stripe_customer_id NOT ILIKE ?', '%balanced%')} - # is this card unused - scope :unused, -> { references(:charges,:donations, :tickets).includes(:charges, :donations, :tickets).where('donations.id IS NULL AND charges.id IS NULL AND tickets.id IS NULL')} - - # these are stripe_card_ids which are on multiple cards - scope :nonunique_stripe_card_ids, -> {where('stripe_card_id IS NOT NULL').group('stripe_card_id').having('COUNT(id) > 1').select('stripe_card_id, COUNT(id)') } - - # cards we feel we can detach from Stripe due to nonuse - # this are cards which: - # * have a unique stripe card id (not on another Card object) - # * owned by a Supporter - # * never been on associated with a charge, donation or ticket - # * was created more than a month ago - # * not originally from the Balanced service used before Stripe - def self.detachable_because_of_nonuse - # we want cards which are: - possible_cards = not_legacy_balanced.unused.held_by_supporters.where('cards.created_at < ?', 1.month.ago).where('cards.stripe_card_id IS NOT NULL') - - nonunique_ids = nonunique_stripe_card_ids.map{|i| i.stripe_card_id} - cards_without_unique_stripe_card_ids = possible_cards.select{|i| !nonunique_ids.include? i.stripe_card_id} - end - end - end - + attr_accessible \ + :cardholders_name, # str (name associated with this card) + :email, # str (cache the email associated with this card) + :name, # str (readable card name, eg. Visa *1234) + :failure_message, # accessor for temporarily storing the stripe decline message + :status, # str + :stripe_card_token, # str + :stripe_card_id, # str + :stripe_customer_id, # str + :holder, :holder_id, :holder_type, # polymorphic cardholder association + :inactive # a card is inactive. This is currently only meaningful for nonprofit cards + + scope :amex_only, -> { where("cards.name ILIKE ? OR cards.name ILIKE ?", "American Express%", "amex%") } + scope :not_amex, -> { where("cards.name NOT ILIKE ? AND cards.name NOT ILIKE ?", "American Express%", "amex%") } + + scope :held_by_nonprofits, -> { where("cards.holder_type = ? ", "Nonprofit") } + scope :held_by_supporters, -> { where("cards.holder_type = ? ", "Supporter") } + + attr_accessor :failure_message + + belongs_to :holder, polymorphic: true + has_many :charges + has_many :donations + has_many :recurring_donations, through: :donations + has_many :tickets + has_one :source_token, as: :tokenizable + + # an helpful method for getting the supporter when it's the holder + def supporter + if holder_type == "Supporter" + holder + end + end + + # an helpful method for getting the supporter's nonprofit + # when the supporter is the holder + def supporter_nonprofit + supporter&.nonprofit + end + + def amex? + !!(name =~ /American Express.*/i) + end + + def not_amex? + !amex? + end + + def stripe_customer + @stripe_customer ||= Stripe::Customer.retrieve(stripe_customer_id) + end + + def stripe_card + @stripe_card ||= stripe_customer.sources.retrieve(stripe_card_id) + end + + concerning :Maintenance do + included do + # is this originally from balanced? + scope :legacy_balanced, -> { where("cards.stripe_customer_id ILIKE ?", "%balanced%") } + # Is this originally not from balanced + scope :not_legacy_balanced, -> { where("cards.stripe_customer_id NOT ILIKE ?", "%balanced%") } + # is this card unused + scope :unused, -> { references(:charges, :donations, :tickets).includes(:charges, :donations, :tickets).where("donations.id IS NULL AND charges.id IS NULL AND tickets.id IS NULL") } + + # these are stripe_card_ids which are on multiple cards + scope :nonunique_stripe_card_ids, -> { where.not(stripe_card_id: nil).group("stripe_card_id").having("COUNT(id) > 1").select("stripe_card_id, COUNT(id)") } + + # cards we feel we can detach from Stripe due to nonuse + # this are cards which: + # * have a unique stripe card id (not on another Card object) + # * owned by a Supporter + # * never been on associated with a charge, donation or ticket + # * was created more than a month ago + # * not originally from the Balanced service used before Stripe + def self.detachable_because_of_nonuse + # we want cards which are: + possible_cards = not_legacy_balanced.unused.held_by_supporters.where("cards.created_at < ?", 1.month.ago).where.not(cards: {stripe_card_id: nil}) + + nonunique_ids = nonunique_stripe_card_ids.map { |i| i.stripe_card_id } + possible_cards.select { |i| !nonunique_ids.include? i.stripe_card_id } + end + end + end end diff --git a/app/models/charge.rb b/app/models/charge.rb index a11bde269..a3e80112b 100644 --- a/app/models/charge.rb +++ b/app/models/charge.rb @@ -2,64 +2,60 @@ # A Charge represents a potential debit to a nonprofit's account on a credit card donation action. class Charge < ApplicationRecord - - attr_accessible \ - :amount, - :fee, - :stripe_charge_id, - :status - - - has_one :campaign, through: :donation - has_one :recurring_donation, through: :donation - has_one :stripe_dispute, primary_key: :stripe_charge_id, foreign_key: :stripe_charge_id - has_many :tickets - has_many :events, through: :tickets - has_many :refunds - has_many :disputes - belongs_to :supporter - belongs_to :card - belongs_to :direct_debit_detail - belongs_to :nonprofit - belongs_to :donation - belongs_to :payment - belongs_to :stripe_charge_object, primary_key: "stripe_charge_id", foreign_key: "stripe_charge_id", class_name: "StripeCharge" - - scope :paid, ->{where(status: ["available", "pending", "disbursed"])} - scope :not_paid, ->{where(status: [nil, "failed"])} - scope :available, ->{where(status: "available")} - scope :pending, ->{where(status: "pending")} - scope :disbursed, ->{where(status: "disbursed")} - - has_many :manual_balance_adjustments, as: :entity - - def paid? - self.status.in?(%w[available pending disbursed]) - end - - # Is this charge disbursed as part of a payout? - def disbursed? - status == 'disbursed' - end - - def stripe_charge(*expand) - Stripe::Charge.retrieve({id: stripe_charge_id, expand: expand}) - end - - def stripe_fee - stripe_charge('balance_transaction').balance_transaction.fee - end - - - concerning :Maintenance do - included do - scope :with_missing_stripe_charge_objects, -> { where('charges.stripe_charge_id IS NOT NULL AND stripe_charges.id IS NULL').includes(:stripe_charge_object).references(:stripe_charges)} - end - end - - def calculate_stripe_fee - source = stripe_charge_object.stripe_object.source - stripe_fee = nonprofit.calculate_stripe_fee(source: source, amount: amount, at: created_at) - end - + attr_accessible \ + :amount, + :fee, + :stripe_charge_id, + :status + + has_one :campaign, through: :donation + has_one :recurring_donation, through: :donation + has_one :stripe_dispute, primary_key: :stripe_charge_id, foreign_key: :stripe_charge_id + has_many :tickets + has_many :events, through: :tickets + has_many :refunds + has_many :disputes + belongs_to :supporter + belongs_to :card + belongs_to :direct_debit_detail + belongs_to :nonprofit + belongs_to :donation + belongs_to :payment + belongs_to :stripe_charge_object, primary_key: "stripe_charge_id", foreign_key: "stripe_charge_id", class_name: "StripeCharge" + + scope :paid, -> { where(status: ["available", "pending", "disbursed"]) } + scope :not_paid, -> { where(status: [nil, "failed"]) } + scope :available, -> { where(status: "available") } + scope :pending, -> { where(status: "pending") } + scope :disbursed, -> { where(status: "disbursed") } + + has_many :manual_balance_adjustments, as: :entity + + def paid? + status.in?(%w[available pending disbursed]) + end + + # Is this charge disbursed as part of a payout? + def disbursed? + status == "disbursed" + end + + def stripe_charge(*expand) + Stripe::Charge.retrieve({id: stripe_charge_id, expand: expand}) + end + + def stripe_fee + stripe_charge("balance_transaction").balance_transaction.fee + end + + concerning :Maintenance do + included do + scope :with_missing_stripe_charge_objects, -> { where("charges.stripe_charge_id IS NOT NULL AND stripe_charges.id IS NULL").includes(:stripe_charge_object).references(:stripe_charges) } + end + end + + def calculate_stripe_fee + source = stripe_charge_object.stripe_object.source + nonprofit.calculate_stripe_fee(source: source, amount: amount, at: created_at) + end end diff --git a/app/models/comment.rb b/app/models/comment.rb index 6f4b9e52c..13d262ede 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,35 +1,33 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Comment < ApplicationRecord + attr_accessible \ + :host_id, :host_type, # parent: Event, Campaign, nil + :profile_id, + :body - attr_accessible \ - :host_id, :host_type, #parent: Event, Campaign, nil - :profile_id, - :body + validates :profile, presence: true + validates :body, presence: true, length: {maximum: 200} - validates :profile, :presence => true - validates :body, :presence => true, :length => {:maximum => 200} + has_one :activity, as: :attachment, dependent: :destroy + belongs_to :host, polymorphic: true + belongs_to :donation + belongs_to :profile - has_one :activity, :as => :attachment, :dependent => :destroy - belongs_to :host, :polymorphic => true - belongs_to :donation - belongs_to :profile + before_validation(on: :create) do + remove_newlines + end - before_validation(:on => :create) do - remove_newlines - end - - after_create do - self.create_activity({ - :desc => 'commented', - :profile_id => self.profile_id, - :host_id => self.host_id, - :host_type => self.host_type, - :body => self.body - }) - end - - def remove_newlines - self.body = self.body && self.body.gsub(/\n/,'') - end + after_create do + create_activity({ + desc: "commented", + profile_id: profile_id, + host_id: host_id, + host_type: host_type, + body: body + }) + end + def remove_newlines + self.body = body && body.delete("\n") + end end diff --git a/app/models/concerns/model/as_moneyable.rb b/app/models/concerns/model/as_moneyable.rb index fe4d40d29..94fc35344 100644 --- a/app/models/concerns/model/as_moneyable.rb +++ b/app/models/concerns/model/as_moneyable.rb @@ -3,19 +3,19 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Model::AsMoneyable - extend ActiveSupport::Concern - class_methods do + extend ActiveSupport::Concern + class_methods do def moneyable_attributes @moneyable_attributes ||= [] end - # For every attribute in attr, this creates a new getter with the postfix of `_as_money` that - # returns the the attribute as an Amount, with the currency from + # For every attribute in attr, this creates a new getter with the postfix of `_as_money` that + # returns the the attribute as an Amount, with the currency from # the currency attribute of the class. def as_money(*attr) attr.each do |a| moneyable_attributes << a - class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition + class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition def #{a}_as_money Amount.new(#{a} || 0, currency) end @@ -23,4 +23,4 @@ def #{a}_as_money end end end -end \ No newline at end of file +end diff --git a/app/models/concerns/model/calculated_names.rb b/app/models/concerns/model/calculated_names.rb index 3d9a4735a..5efdf371c 100644 --- a/app/models/concerns/model/calculated_names.rb +++ b/app/models/concerns/model/calculated_names.rb @@ -3,10 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Model::CalculatedNames - extend ActiveSupport::Concern + extend ActiveSupport::Concern included do def calculated_first_name - name_parts = name&.strip&.split(' ')&.map(&:strip) + name_parts = name&.strip&.split(" ")&.map(&:strip) case name_parts&.count || 0 when 0 nil @@ -16,9 +16,9 @@ def calculated_first_name name_parts[0..-2].join(" ") end end - + def calculated_last_name - name_parts = name&.strip&.split(' ')&.map(&:strip) + name_parts = name&.strip&.split(" ")&.map(&:strip) case name_parts&.count || 0 when 0 nil @@ -29,4 +29,4 @@ def calculated_last_name end end end -end \ No newline at end of file +end diff --git a/app/models/concerns/model/created_timeable.rb b/app/models/concerns/model/created_timeable.rb index 1aa333eec..c249812a6 100644 --- a/app/models/concerns/model/created_timeable.rb +++ b/app/models/concerns/model/created_timeable.rb @@ -5,14 +5,14 @@ # this mixin provides a way to set the :created attribute when the model is initialized unless it's already been provided module Model::CreatedTimeable - extend ActiveSupport::Concern - included do - after_initialize :set_created_if_needed + extend ActiveSupport::Concern + included do + after_initialize :set_created_if_needed - private + private - def set_created_if_needed - self[:created] = Time.current unless self[:created] - end - end + def set_created_if_needed + self[:created] = Time.current unless self[:created] + end + end end diff --git a/app/models/concerns/model/houidable.rb b/app/models/concerns/model/houidable.rb index 3b0202ab4..8d86ea56d 100644 --- a/app/models/concerns/model/houidable.rb +++ b/app/models/concerns/model/houidable.rb @@ -5,53 +5,53 @@ # rubocop:disable Layout/TrailingWhitespace # we do this becuase rubocop is bizarrely crashing on this file module Model::Houidable - extend ActiveSupport::Concern - class_methods do - ### - # @description: Simplifies using HouIDs for an ActiveRecord class. A Houid (pronounced "Hoo-id") is a unique - # identifier for an object. Houids have the format of: prefix_{22 random alphanumeric characters}. A prefix - # consists of lowercase alphabetical characters. Each class must have its own unique prefix. All of the Houids - # generated for that class will use that prefix. - # - # Given a prefix, adds the following features to a ActiveRecord class: - # - Sets a HouID to the id after object initialization (on "after_initialize" callback) if - # it hasn't already been set - # - Adds a "before_houid_set" and "after_houid_set" callbacks in case you want do - # somethings before or after that happens - # - Adds "before_houid_set" and "after_houid_set" callbacks if you want to take actions around - # - Adds the following public class methods (and instance methods that delegate to this methods): - # - houid_prefix - returns the prefix as a symbol - # - generate_houid - creates a new HouID with given prefix - # - houid_attribute - the symbol of the attribute on this class that the Houid is assigned to. - # - Adds the following public instance method: - # - to_houid - returns the houid for the instance regardless of what `houid_attribute` is. - # @param prefix {string|Symbol}: the prefix for the HouIDs on this model - # @param houid_attribute {string|Symbol}: the attribute on this model to assign the Houid to. Defaults to :id. - ### - def setup_houid(prefix, houid_attribute = :id) - - ###### - # define_model_callbacks :houid_set - # after_initialize :add_houid - - # # The HouID prefix as a symbol - # def houid_prefix - # :supp - # end - - # # Generates a HouID using the provided houid_prefix - # def generate_houid - # houid_prefix.to_s + "_" + SecureRandom.alphanumeric(22) - # end - - # private - # def add_houid - # run_callbacks(:houid_set) do - # write_attribute(:id, self.generate_houid) unless read_attribute(:id) - # end - # end - ##### - class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition + extend ActiveSupport::Concern + class_methods do + ### + # @description: Simplifies using HouIDs for an ActiveRecord class. A Houid (pronounced "Hoo-id") is a unique + # identifier for an object. Houids have the format of: prefix_{22 random alphanumeric characters}. A prefix + # consists of lowercase alphabetical characters. Each class must have its own unique prefix. All of the Houids + # generated for that class will use that prefix. + # + # Given a prefix, adds the following features to a ActiveRecord class: + # - Sets a HouID to the id after object initialization (on "after_initialize" callback) if + # it hasn't already been set + # - Adds a "before_houid_set" and "after_houid_set" callbacks in case you want do + # somethings before or after that happens + # - Adds "before_houid_set" and "after_houid_set" callbacks if you want to take actions around + # - Adds the following public class methods (and instance methods that delegate to this methods): + # - houid_prefix - returns the prefix as a symbol + # - generate_houid - creates a new HouID with given prefix + # - houid_attribute - the symbol of the attribute on this class that the Houid is assigned to. + # - Adds the following public instance method: + # - to_houid - returns the houid for the instance regardless of what `houid_attribute` is. + # @param prefix {string|Symbol}: the prefix for the HouIDs on this model + # @param houid_attribute {string|Symbol}: the attribute on this model to assign the Houid to. Defaults to :id. + ### + def setup_houid(prefix, houid_attribute = :id) + + ###### + # define_model_callbacks :houid_set + # after_initialize :add_houid + + # # The HouID prefix as a symbol + # def houid_prefix + # :supp + # end + + # # Generates a HouID using the provided houid_prefix + # def generate_houid + # houid_prefix.to_s + "_" + SecureRandom.alphanumeric(22) + # end + + # private + # def add_houid + # run_callbacks(:houid_set) do + # write_attribute(:id, self.generate_houid) unless read_attribute(:id) + # end + # end + ##### + class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition define_model_callbacks :houid_set after_initialize :add_houid @@ -85,9 +85,9 @@ def add_houid write_attribute(self.houid_attribute, self.generate_houid) unless read_attribute(self.houid_attribute) end end - RUBY - end - end + RUBY + end + end end # rubocop:enable Layout/TrailingWhitespace diff --git a/app/models/concerns/model/subtransactable.rb b/app/models/concerns/model/subtransactable.rb index 80c10e4e6..2c3974b55 100644 --- a/app/models/concerns/model/subtransactable.rb +++ b/app/models/concerns/model/subtransactable.rb @@ -3,25 +3,25 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Model::Subtransactable - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do - include Model::Houidable + included do + include Model::Houidable - has_one :subtransaction, as: :subtransactable, dependent: :nullify - has_one :trx, through: :subtransaction, class_name: 'Transaction' - has_one :supporter, through: :trx - has_one :nonprofit, through: :trx + has_one :subtransaction, as: :subtransactable, dependent: :nullify + has_one :trx, through: :subtransaction, class_name: "Transaction" + has_one :supporter, through: :trx + has_one :nonprofit, through: :trx - has_many :subtransaction_payments, -> { extending ModelExtensions::PaymentsExtension }, through: :subtransaction + has_many :subtransaction_payments, -> { extending ModelExtensions::PaymentsExtension }, through: :subtransaction - delegate :currency, to: :nonprofit + delegate :currency, to: :nonprofit - # Handle a completed refund from a legacy Refund object - # Implement this in your specific subtransaction class if you want to use it. - def process_refund(refund) - raise NotImplementedError, - "You need to implement 'process_refund' in your specific subtransaction class" - end - end + # Handle a completed refund from a legacy Refund object + # Implement this in your specific subtransaction class if you want to use it. + def process_refund(refund) + raise NotImplementedError, + "You need to implement 'process_refund' in your specific subtransaction class" + end + end end diff --git a/app/models/concerns/model/subtransaction_paymentable.rb b/app/models/concerns/model/subtransaction_paymentable.rb index 60444723f..374329099 100644 --- a/app/models/concerns/model/subtransaction_paymentable.rb +++ b/app/models/concerns/model/subtransaction_paymentable.rb @@ -3,20 +3,20 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Model::SubtransactionPaymentable - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do - include Model::Houidable + included do + include Model::Houidable - has_one :subtransaction_payment, as: :paymentable, dependent: :destroy - has_one :trx, through: :subtransaction_payment - has_one :supporter, through: :subtransaction_payment - has_one :nonprofit, through: :subtransaction_payment + has_one :subtransaction_payment, as: :paymentable, dependent: :destroy + has_one :trx, through: :subtransaction_payment + has_one :supporter, through: :subtransaction_payment + has_one :nonprofit, through: :subtransaction_payment - has_one :subtransaction, through: :subtransaction_payment + has_one :subtransaction, through: :subtransaction_payment - has_many :object_events, as: :event_entity + has_many :object_events, as: :event_entity - delegate :currency, to: :nonprofit - end + delegate :currency, to: :nonprofit + end end diff --git a/app/models/concerns/model/trx_assignable.rb b/app/models/concerns/model/trx_assignable.rb index 760ecd568..127ea2fb4 100644 --- a/app/models/concerns/model/trx_assignable.rb +++ b/app/models/concerns/model/trx_assignable.rb @@ -3,18 +3,18 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE module Model::TrxAssignable - extend ActiveSupport::Concern + extend ActiveSupport::Concern - included do - include Model::Houidable + included do + include Model::Houidable - has_one :transaction_assignment, as: :assignable - has_one :trx, through: :transaction_assignment, class_name: 'Transaction', foreign_key: 'transaction_id' - has_one :supporter, through: :transaction_assignment - has_one :nonprofit, through: :transaction_assignment - - delegate :currency, to: :nonprofit + has_one :transaction_assignment, as: :assignable + has_one :trx, through: :transaction_assignment, class_name: "Transaction", foreign_key: "transaction_id" + has_one :supporter, through: :transaction_assignment + has_one :nonprofit, through: :transaction_assignment - has_many :object_events, as: :event_entity - end + delegate :currency, to: :nonprofit + + has_many :object_events, as: :event_entity + end end diff --git a/app/models/custom_field_join.rb b/app/models/custom_field_join.rb index 0d96a3788..a397460e1 100644 --- a/app/models/custom_field_join.rb +++ b/app/models/custom_field_join.rb @@ -1,25 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CustomFieldJoin < ApplicationRecord + attr_accessible \ + :supporter, :supporter_id, + :custom_field_master, :custom_field_master_id, + :value - attr_accessible \ - :supporter, :supporter_id, - :custom_field_master, :custom_field_master_id, - :value + validates :custom_field_master, presence: true - validates :custom_field_master, presence: true - - belongs_to :custom_field_master + belongs_to :custom_field_master belongs_to :supporter - def self.create_with_name(nonprofit, h) - cfm = nonprofit.custom_field_masters.find_by_name(h['name']) - if cfm.nil? - cfm = nonprofit.custom_field_masters.create(name: h['name']) - end - self.create({value: h['value'], custom_field_master_id: cfm.id, supporter_id: h['supporter_id']}) - end - - def name; custom_field_master.name; end + def self.create_with_name(nonprofit, h) + cfm = nonprofit.custom_field_masters.find_by_name(h["name"]) + if cfm.nil? + cfm = nonprofit.custom_field_masters.create(name: h["name"]) + end + create({value: h["value"], custom_field_master_id: cfm.id, supporter_id: h["supporter_id"]}) + end + def name + custom_field_master.name + end end - diff --git a/app/models/custom_field_master.rb b/app/models/custom_field_master.rb index aea45a2a1..832ed093f 100644 --- a/app/models/custom_field_master.rb +++ b/app/models/custom_field_master.rb @@ -1,25 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CustomFieldMaster < ApplicationRecord + attr_accessible \ + :nonprofit, :nonprofit_id, + :name, + :deleted, + :created_at - attr_accessible \ - :nonprofit, :nonprofit_id, - :name, - :deleted, - :created_at + validates :name, presence: true + validate :no_dupes, on: :create - validates :name, presence: true - validate :no_dupes, on: :create + belongs_to :nonprofit + has_many :custom_field_joins, dependent: :destroy + has_many :supporters, through: :custom_field_joins - belongs_to :nonprofit - has_many :custom_field_joins, dependent: :destroy - has_many :supporters, through: :custom_field_joins - - scope :not_deleted, ->{where(deleted: [nil,false])} - - def no_dupes - return self if nonprofit.nil? - errors.add(:base, "Duplicate custom field") if nonprofit.custom_field_masters.not_deleted.where(name: name).any? - end + scope :not_deleted, -> { where(deleted: [nil, false]) } + def no_dupes + return self if nonprofit.nil? + errors.add(:base, "Duplicate custom field") if nonprofit.custom_field_masters.not_deleted.where(name: name).any? + end end - diff --git a/app/models/direct_debit_detail.rb b/app/models/direct_debit_detail.rb index f3ae07dbd..d75a97d97 100644 --- a/app/models/direct_debit_detail.rb +++ b/app/models/direct_debit_detail.rb @@ -4,5 +4,5 @@ class DirectDebitDetail < ApplicationRecord has_many :donations has_many :charges - belongs_to :holder, class_name: 'Supporter' + belongs_to :holder, class_name: "Supporter" end diff --git a/app/models/dispute.rb b/app/models/dispute.rb index 91230da11..e7d9f7262 100644 --- a/app/models/dispute.rb +++ b/app/models/dispute.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Dispute < ApplicationRecord - Reasons = [:unrecognized, :duplicate, :fraudulent, :subscription_canceled, :product_unacceptable, :product_not_received, :unrecognized, :credit_not_processed, :goods_services_returned_or_refused, :goods_services_cancelled, :incorrect_account_details, :insufficient_funds, :bank_cannot_process, :debit_not_authorized, :general] Statuses = [:needs_response, :under_review, :won, :lost] @@ -11,7 +10,7 @@ class Dispute < ApplicationRecord :status, :reason, :started_at - + attr_accessible \ :withdrawal_transaction, :reinstatement_transaction @@ -25,18 +24,17 @@ class Dispute < ApplicationRecord has_one :original_payment, through: :charge, source: :payment has_many :activities, as: :attachment do - def create(event_type, event_time, attributes=nil, options={}, &block) - attributes = proxy_association.owner.build_activity_attributes(event_type, event_time) .merge(attributes || {}) - proxy_association.create(attributes, options, &block) - end + def create(event_type, event_time, attributes = nil, options = {}, &block) + attributes = proxy_association.owner.build_activity_attributes(event_type, event_time).merge(attributes || {}) + proxy_association.create(attributes, options, &block) + end - def build(event_type, event_time, attributes=nil, options={}, &block) - attributes = proxy_association.owner.build_activity_attributes(event_type, event_time).merge(attributes || {}) - proxy_association.build(attributes, options, &block) - end + def build(event_type, event_time, attributes = nil, options = {}, &block) + attributes = proxy_association.owner.build_activity_attributes(event_type, event_time).merge(attributes || {}) + proxy_association.build(attributes, options, &block) + end end - def withdrawal_transaction dispute_transactions&.first end @@ -50,30 +48,30 @@ def get_original_payment end def build_activity_json(event_type) - dispute = self - original_payment = dispute.original_payment - case event_type - when 'DisputeCreated', 'DisputeUpdated', 'DisputeLost', 'DisputeWon' - return { + dispute = self + original_payment = dispute.original_payment + case event_type + when "DisputeCreated", "DisputeUpdated", "DisputeLost", "DisputeWon" + { gross_amount: dispute.gross_amount, - reason: dispute.reason, - status: dispute.status, - original_id: original_payment.id, - original_kind: original_payment.kind, - original_gross_amount: original_payment.gross_amount, + reason: dispute.reason, + status: dispute.status, + original_id: original_payment.id, + original_kind: original_payment.kind, + original_gross_amount: original_payment.gross_amount, original_date: original_payment.date, started_at: dispute.started_at } else - raise RuntimeError, "#{event_type} is not a valid Dispute event type" - end - end + raise "#{event_type} is not a valid Dispute event type" + end + end def build_activity_attributes(event_type, event_time) dispute = self - case event_type - when 'DisputeCreated', 'DisputeUpdated', 'DisputeLost', 'DisputeWon' - return { + case event_type + when "DisputeCreated", "DisputeUpdated", "DisputeLost", "DisputeWon" + { kind: event_type, date: event_time, nonprofit: dispute.nonprofit, @@ -81,8 +79,7 @@ def build_activity_attributes(event_type, event_time) json_data: build_activity_json(event_type) } else - raise RuntimeError, "#{event_type} is not a valid Dispute event type" - end - end + raise "#{event_type} is not a valid Dispute event type" + end + end end - diff --git a/app/models/dispute_transaction.rb b/app/models/dispute_transaction.rb index 627f8c451..a657337cd 100644 --- a/app/models/dispute_transaction.rb +++ b/app/models/dispute_transaction.rb @@ -2,11 +2,11 @@ class DisputeTransaction < ApplicationRecord belongs_to :dispute belongs_to :payment attr_accessible :gross_amount, :disbursed, :payment, :fee_total, - :stripe_transaction_id, :date + :stripe_transaction_id, :date has_one :nonprofit, through: :dispute has_one :supporter, through: :dispute - has_many :manual_balance_adjustments, as: :entity + has_many :manual_balance_adjustments, as: :entity def gross_amount=(gross_amount) write_attribute(:gross_amount, gross_amount) @@ -23,6 +23,7 @@ def from_donation? end private + def calculate_net self.net_amount = gross_amount + fee_total end diff --git a/app/models/donation.rb b/app/models/donation.rb index 6915a1433..1827c916c 100644 --- a/app/models/donation.rb +++ b/app/models/donation.rb @@ -1,68 +1,67 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Donation < ApplicationRecord + before_save :set_anonymous - before_save :set_anonymous - - attr_accessible \ - :date, # datetime (when this donation was made) - :amount, # int (in cents) - :recurring, # bool - :anonymous, # bool - :email, # str (cached email of the donor) - :designation, # text - :dedication, # text - :comment, # text - :origin_url, # text - :nonprofit_id, :nonprofit, - :card_id, :card, # Card with which any charges were made - :supporter_id, :supporter, - :profile_id, :profile, - :campaign_id, :campaign, - :payment_id, :payment, - :event_id, :event, - :direct_debit_detail_id, :direct_debit_detail, + attr_accessible \ + :date, # datetime (when this donation was made) + :amount, # int (in cents) + :recurring, # bool + :anonymous, # bool + :email, # str (cached email of the donor) + :designation, # text + :dedication, # text + :comment, # text + :origin_url, # text + :nonprofit_id, :nonprofit, + :card_id, :card, # Card with which any charges were made + :supporter_id, :supporter, + :profile_id, :profile, + :campaign_id, :campaign, + :payment_id, :payment, + :event_id, :event, + :direct_debit_detail_id, :direct_debit_detail, :payment_provider - # fts is generated via a trigger - attr_readonly :fts + # fts is generated via a trigger + attr_readonly :fts - validates :amount, presence: true, numericality: { only_integer: true } - validates :supporter, presence: true - validates :nonprofit, presence: true - validates_associated :charges - validates :payment_provider, inclusion: { in: ['credit_card', 'sepa'] }, allow_blank: true + validates :amount, presence: true, numericality: {only_integer: true} + validates :supporter, presence: true + validates :nonprofit, presence: true + validates_associated :charges + validates :payment_provider, inclusion: {in: ["credit_card", "sepa"]}, allow_blank: true - has_many :charges - has_many :campaign_gifts, dependent: :destroy - has_many :campaign_gift_options, through: :campaign_gifts - has_many :activities, as: :attachment, dependent: :destroy - has_many :payments - has_one :recurring_donation - has_one :payment - has_one :offsite_payment - has_one :tracking - has_many :modern_donations - belongs_to :supporter - belongs_to :card - belongs_to :direct_debit_detail - belongs_to :profile - belongs_to :nonprofit - belongs_to :campaign - belongs_to :event + has_many :charges + has_many :campaign_gifts, dependent: :destroy + has_many :campaign_gift_options, through: :campaign_gifts + has_many :activities, as: :attachment, dependent: :destroy + has_many :payments + has_one :recurring_donation + has_one :payment + has_one :offsite_payment + has_one :tracking + has_many :modern_donations + belongs_to :supporter + belongs_to :card + belongs_to :direct_debit_detail + belongs_to :profile + belongs_to :nonprofit + belongs_to :campaign + belongs_to :event - scope :anonymous, -> {where(anonymous: true)} + scope :anonymous, -> { where(anonymous: true) } - def campaign_gift_purchase? - campaign_gifts.any? - end + def campaign_gift_purchase? + campaign_gifts.any? + end - def actual_donation? - campaign_gifts.none? - end + def actual_donation? + campaign_gifts.none? + end - private + private - def set_anonymous - update_attributes(anonymous: false) if anonymous.nil? - end + def set_anonymous + update_attributes(anonymous: false) if anonymous.nil? + end end diff --git a/app/models/drip_email_list.rb b/app/models/drip_email_list.rb index 8fd7bd6bd..d6099dcc9 100644 --- a/app/models/drip_email_list.rb +++ b/app/models/drip_email_list.rb @@ -1,16 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class DripEmailList < ApplicationRecord + validates :mailchimp_list_id, presence: true - validates :mailchimp_list_id, :presence => true - - # the path on the Mailchimp api for the list - def list_path + # the path on the Mailchimp api for the list + def list_path "lists/#{mailchimp_list_id}" - end - - # the path on the Mailchimp api for the list's members - def list_members_path - list_path + "/members" - end + end + + # the path on the Mailchimp api for the list's members + def list_members_path + list_path + "/members" + end end diff --git a/app/models/e_tap_import.rb b/app/models/e_tap_import.rb index dbdceb514..3269d0337 100644 --- a/app/models/e_tap_import.rb +++ b/app/models/e_tap_import.rb @@ -1,17 +1,16 @@ class ETapImport < ApplicationRecord - attr_accessible :nonprofit belongs_to :nonprofit - has_many :e_tap_import_journal_entries do + has_many :e_tap_import_journal_entries do def create_from_csv(filename) - CSV.read(filename, headers:true).each do |row| + CSV.read(filename, headers: true).each do |row| create(row: row.to_h) end end end - has_many :e_tap_import_contacts do + has_many :e_tap_import_contacts do def create_from_csv(filename) - CSV.read(filename, headers:true).each do |row| + CSV.read(filename, headers: true).each do |row| create(row: row.to_h) end end @@ -19,17 +18,15 @@ def create_from_csv(filename) has_many :reassignments def self.create_import(nonprofit, journal_file, contacts_file) - transaction do - e_tap_import = create(nonprofit:nonprofit) + e_tap_import = create(nonprofit: nonprofit) e_tap_import.e_tap_import_contacts.create_from_csv(contacts_file) e_tap_import.e_tap_import_journal_entries.create_from_csv(journal_file) end end - def process(user) - e_tap_import_journal_entries.order('e_tap_import_journal_entries.id ASC').each do |entry| + e_tap_import_journal_entries.order("e_tap_import_journal_entries.id ASC").each do |entry| transaction do if entry.unprocessed? entry.to_wrapper.process(user) diff --git a/app/models/e_tap_import_contact.rb b/app/models/e_tap_import_contact.rb index 01d69b3d0..cba0d6ee8 100644 --- a/app/models/e_tap_import_contact.rb +++ b/app/models/e_tap_import_contact.rb @@ -2,10 +2,10 @@ class ETapImportContact < ApplicationRecord attr_accessible :row, :nonprofit belongs_to :e_tap_import has_one :nonprofit, through: :e_tap_import - + def supporters - nonprofit.supporters.not_deleted.includes(:custom_field_joins => :custom_field_master) - .where('custom_field_masters.name = ?', "E-Tapestry Id #") + nonprofit.supporters.not_deleted.includes(custom_field_joins: :custom_field_master) + .where("custom_field_masters.name = ?", "E-Tapestry Id #") .where("custom_field_joins.value = ?", account_id.to_s).references(:custom_field_joins, :custom_field_masters) end @@ -14,17 +14,17 @@ def supporter end def self.with_supporters - select{|i| !i.supporter.nil?} + select { |i| !i.supporter.nil? } end def self.without_supporters - select{|i| i.supporter.nil?} + select { |i| i.supporter.nil? } end def self.matched_by_address - cfm = CustomFieldMaster.find_by_name('Got Supporter by address') + cfm = CustomFieldMaster.find_by_name("Got Supporter by address") - select{|i| i.supporter&.custom_field_joins&.select{|i| i.custom_field_master_id == cfm.id}&.any?} + select { |i| i.supporter&.custom_field_joins&.select { |i| i.custom_field_master_id == cfm.id }&.any? } end def self.find_by_account_id(account_id) @@ -32,7 +32,7 @@ def self.find_by_account_id(account_id) end def journal_entries - e_tap_import.e_tap_import_journal_entries.by_account(row['Account Number']) + e_tap_import.e_tap_import_journal_entries.by_account(row["Account Number"]) end def self.find_by_account_name(account_name, account_email, original_account_id) @@ -43,36 +43,34 @@ def self.find_by_account_name(account_name, account_email, original_account_id) query.where("NOT row @> '{\"Account Number\": \"#{original_account_id}\"}'").first end - def create_or_update_CUSTOM(known_supporter=nil) - - custom_fields_to_save = self.to_custom_fields; - got_supporter_via_address = false + def create_or_update_CUSTOM(known_supporter = nil) + custom_fields_to_save = to_custom_fields latest_journal_entry = journal_entries.first - + supporter = known_supporter || - self.supporter || - e_tap_import.nonprofit.supporters.not_deleted.where("name = ? AND LOWER(COALESCE(email, '')) = ?", self.name, self.email&.downcase).first + self.supporter || + e_tap_import.nonprofit.supporters.not_deleted.where("name = ? AND LOWER(COALESCE(email, '')) = ?", name, email&.downcase).first - if !supporter && !(self.address.blank? && self.state.blank? && self.city.blank?) - supporter = e_tap_import.nonprofit.supporters.not_deleted.where('name = ? AND address = ? AND state_code = ? AND city = ?',self.name,self.address,self.state, self.city).first + if !supporter && !(address.blank? && state.blank? && city.blank?) + supporter = e_tap_import.nonprofit.supporters.not_deleted.where("name = ? AND address = ? AND state_code = ? AND city = ?", name, address, state, city).first if supporter.present? - custom_fields_to_save = custom_fields_to_save + [['Got Supporter by address', "#{self.name}, #{self.address}, #{self.state}, #{self.city}"]] - got_supporter_via_address = true + custom_fields_to_save += [["Got Supporter by address", "#{name}, #{address}, #{state}, #{city}"]] + true end end - + # is this also relate to the latest payment if supporter - if (latest_journal_entry&.to_wrapper&.date || Time.at(0)) >= (supporter.payments.order('date DESC').first&.date || Time.at(0)) # + if (latest_journal_entry&.to_wrapper&.date || Time.at(0)) >= (supporter.payments.order("date DESC").first&.date || Time.at(0)) puts "update the supporter info" begin # did we overwrite the email? if supporter.persisted? && supporter.email && to_supporter_args[:email] && supporter.email.downcase != to_supporter_args[:email].downcase - cfj = supporter.custom_field_joins.joins(:custom_field_master).where('custom_field_masters.name = ?', "Overwrote previous email").references(:custom_field_masters).first - val = (cfj&.split(',')|| []) + [supporter.email] - custom_fields_to_save = custom_fields_to_save + [['Overwrote previous email', val.join(',')]] + cfj = supporter.custom_field_joins.joins(:custom_field_master).where("custom_field_masters.name = ?", "Overwrote previous email").references(:custom_field_masters).first + val = (cfj&.split(",") || []) + [supporter.email] + custom_fields_to_save += [["Overwrote previous email", val.join(",")]] end - supporter.update(self.to_supporter_args) + supporter.update(to_supporter_args) rescue PG::NotNullViolation => e byebug raise e @@ -81,10 +79,10 @@ def create_or_update_CUSTOM(known_supporter=nil) puts "do nothing!" end else - supporter = e_tap_import.nonprofit.supporters.create(self.to_supporter_args) + supporter = e_tap_import.nonprofit.supporters.create(to_supporter_args) end - - InsertCustomFieldJoins.find_or_create(e_tap_import.nonprofit.id, [supporter.id], custom_fields_to_save) if custom_fields_to_save.any? + + InsertCustomFieldJoins.find_or_create(e_tap_import.nonprofit.id, [supporter.id], custom_fields_to_save) if custom_fields_to_save.any? supporter end @@ -93,80 +91,69 @@ def journal_entries end def name - row['Account Name'] || "" + row["Account Name"] || "" end def account_id - row['Account Number'] + row["Account Number"] end def organization - row['Company'] + row["Company"] end def address - row['Parsed Address'] || "" - end - - def city - - row['Parsed City'] || "" + row["Parsed Address"] || "" + end - end + def city + row["Parsed City"] || "" + end - def zip_code - row['Parsed ZIP Code'] || "" - end + def zip_code + row["Parsed ZIP Code"] || "" + end - def state - row['Parsed State'] || "" - end - - def country - row['Parsed Country'] || "" - end + def state + row["Parsed State"] || "" + end - + def country + row["Parsed Country"] || "" + end def email if emails.count > 0 emails[0] - else - nil end end - def email_address2 if emails.count > 1 emails[1] - else - nil - end; + end end def email_address3 if emails.count > 2 emails[2] - else - nil end end def full_address - row['Full Address with Country (Single Line)'] || "" + row["Full Address with Country (Single Line)"] || "" end def church_parish - row['County'] + row["County"] end def created_at - row['Creation Date'] + row["Creation Date"] end def created_by - row['Created By'] + row["Created By"] end def envelope_salutation @@ -176,24 +163,18 @@ def envelope_salutation def supporter_phone if phone_numbers.count > 0 phone_numbers[0] - else - nil end end def supporter_phone_2 if phone_numbers.count > 1 phone_numbers[1] - else - nil end end def supporter_phone_3 if phone_numbers.count > 2 phone_numbers[2] - else - nil end end @@ -217,50 +198,49 @@ def to_supporter_args end def to_custom_fields - custom_fields = [['E-Tapestry Id #', account_id]] + custom_fields = [["E-Tapestry Id #", account_id]] if supporter_phone_2 - custom_fields += [['Supporter Phone 2', supporter_phone_2]] + custom_fields += [["Supporter Phone 2", supporter_phone_2]] end if supporter_phone_3 - custom_fields += [['Supporter Phone 3', supporter_phone_3]] + custom_fields += [["Supporter Phone 3", supporter_phone_3]] end - + if email_address2 - custom_fields += [['Email Address 2', email_address2]] + custom_fields += [["Email Address 2", email_address2]] end if email_address3 - custom_fields += [['Email Address 3', email_address3]] + custom_fields += [["Email Address 3", email_address3]] end if church_parish - custom_fields += [['Church Parish', church_parish]] + custom_fields += [["Church Parish", church_parish]] end - if envelope_salutation - custom_fields += [['Envelope Salutation', envelope_salutation]] + if envelope_salutation + custom_fields += [["Envelope Salutation", envelope_salutation]] end if created_at - custom_fields += [['Created At', created_at]] + custom_fields += [["Created At", created_at]] end - + if created_by - custom_fields += [['Created By', created_by]] + custom_fields += [["Created By", created_by]] end custom_fields end def emails - [row['Email Address 1'], row['Email Address 2'], row['Email Address 3']].select{|i| i.present?} + [row["Email Address 1"], row["Email Address 2"], row["Email Address 3"]].select { |i| i.present? } end private def phone_numbers - [row["Phone - Voice"], row['Phone - Mobile'], row['Phone - Cell']].select{|i| i.present?} + [row["Phone - Voice"], row["Phone - Mobile"], row["Phone - Cell"]].select { |i| i.present? } end - end diff --git a/app/models/e_tap_import_journal_entry.rb b/app/models/e_tap_import_journal_entry.rb index 00607ef07..4b82eb478 100644 --- a/app/models/e_tap_import_journal_entry.rb +++ b/app/models/e_tap_import_journal_entry.rb @@ -1,5 +1,4 @@ class ETapImportJournalEntry < ApplicationRecord - def self.by_account(account_id) where("row @> '{\"Account Number\": \"#{account_id}\"}'") end @@ -17,27 +16,27 @@ def supporters_through_journal_entries end def account_id - row['Account Number'] + row["Account Number"] end module Common module Payment def designation - @row['Fund'] + @row["Fund"] end - + def campaign - @row['Campaign'] + @row["Campaign"] end - + def approach - @row['Approach'] + @row["Approach"] end - + def letter - @row['Letter'] + @row["Letter"] end - + def to_payment_note note_contents = [] if campaign.present? @@ -46,82 +45,75 @@ def to_payment_note if approach.present? note_contents += ["Approach: #{approach}"] end - + if letter.present? note_contents += ["Letter: #{letter}"] end - + note_contents.join(" \n") end - + def corresponding_matches? corresponding_payment.gross_amount == amount end - + def create_or_update_payment - # supporter = nil # got_via_address = false - - if corresponding_payment&.supporter - supporter = @entry.contact.create_or_update_CUSTOM(corresponding_payment.supporter) + + supporter = if corresponding_payment&.supporter + @entry.contact.create_or_update_CUSTOM(corresponding_payment.supporter) # byebug if supporter.id == 2362354 - ##sync_contact_with_supporter + # #sync_contact_with_supporter else ## create new supporter - supporter = @entry.contact.create_or_update_CUSTOM + @entry.contact.create_or_update_CUSTOM # byebug if supporter.id == 2362354 end - - - - + if corresponding_payment && corresponding_matches? unless corresponding_payment.tickets.any? byebug unless corresponding_payment.donation UpdateDonation.update_payment(corresponding_payment.donation.id, { - designation: designation, - campaign_id: '', - event_id: '' - }.merge( - corresponding_payment&.donation&.comment ? { - comment: corresponding_payment.donation.comment - } : {} - ).with_indifferent_access - ) + designation: designation, + campaign_id: "", + event_id: "" + }.merge( + corresponding_payment&.donation&.comment ? { + comment: corresponding_payment.donation.comment + } : {} + ).with_indifferent_access) end - return corresponding_payment + corresponding_payment else result = InsertDonation.offsite({ - supporter_id:supporter.id, + supporter_id: supporter.id, nonprofit_id: @entry.e_tap_import.nonprofit.id, date: date.to_s, designation: designation, amount: amount - }.with_indifferent_access.merge(self.methods.include?(:to_payment_note) ? {comment: to_payment_note} : {})) - return ::Payment.find(result[:json]['payment']['id']) + }.with_indifferent_access.merge(methods.include?(:to_payment_note) ? {comment: to_payment_note} : {})) + ::Payment.find(result[:json]["payment"]["id"]) end - end - end module Pledge def pledged - @row['Pledged'] + @row["Pledged"] end - + def pledge_written_off - @row['Pledge Written Off?'] + @row["Pledge Written Off?"] end end module Purchase def authorization_code - gift_type_info['Authorization Code'] + gift_type_info["Authorization Code"] end - + def corresponding_payment if authorization_code.to_i != 0 begin @@ -133,36 +125,33 @@ def corresponding_payment @corresponding_payment ||= nil end end - + def amount - @row['Received'].gsub(/(\D|\.)/, '').to_i + @row["Received"].gsub(/(\D|\.)/, "").to_i end - + def gift_type_info - @row['Gift Type Information'].split(',').map(&:strip).map{|i| i.split(':').map(&:strip)}.map{|row| - - if row.count == 1 - [row[0], nil] - elsif row.count > 2 - [row[0], nil] - else - row - end - }.to_h + @row["Gift Type Information"].split(",").map(&:strip).map { |i| i.split(":").map(&:strip) }.map { |row| + if row.count == 1 + [row[0], nil] + elsif row.count > 2 + [row[0], nil] + else + row + end + }.to_h end end - end - attr_accessible :row + attr_accessible :row has_many :journal_entries_to_items - #has_many :items, through: :journal_entries_to_items, source: :item + # has_many :items, through: :journal_entries_to_items, source: :item belongs_to :e_tap_import - scope :processed, -> {joins(:journal_entries_to_items)} + scope :processed, -> { joins(:journal_entries_to_items) } # scope :unprocessed, -> {includes(:journal_entries_to_items).where("journal_entries_to_items.id = null").references(:journal_entries_to_items)} - def unprocessed? journal_entries_to_items.none? @@ -170,17 +159,17 @@ def unprocessed? def to_wrapper case type - when 'Note' + when "Note" NoteRow.new self - when 'Contact' + when "Contact" ContactEvent.new self - when 'Calendar Item' + when "Calendar Item" CalendarItem.new self - when 'Gift' + when "Gift" Gift.new self - when 'Payment' + when "Payment" CreditPurchase.new self - when 'Pledge' + when "Pledge" Pledge.new self when "Pledge / Payment" PledgePayment.new self @@ -189,82 +178,79 @@ def to_wrapper def self.find_all_by_contact(contact) id = contact.is_a?(ETapImportContact) ? contact.account_id : contact - where("row->>? = ?", 'Account Number', id) + where("row->>? = ?", "Account Number", id) end def type - row['Type'] + row["Type"] end def contact - e_tap_import.e_tap_import_contacts.find_by_account_id(row['Account Number']) + e_tap_import.e_tap_import_contacts.find_by_account_id(row["Account Number"]) end - - class RowWrapper attr_accessor :entry def initialize(entry) @row = entry.row @entry = entry end - + def date - month, day, year = @row['Date'].split('/') - @date ||= ActiveSupport::TimeZone['Central Time (US & Canada)'].local(year, month, day) + month, day, year = @row["Date"].split("/") + @date ||= ActiveSupport::TimeZone["Central Time (US & Canada)"].local(year, month, day) end def supporter - entry.e_tap_import.nonprofit.supporters.not_deleted.includes(:custom_field_joins => :custom_field_master).where('custom_field_masters.name = ? AND custom_field_joins.value = ?', "E-Tapestry Id #", contact.id.to_s).references(:custom_field_masters, :custom_field_joins).first + entry.e_tap_import.nonprofit.supporters.not_deleted.includes(custom_field_joins: :custom_field_master).where("custom_field_masters.name = ? AND custom_field_joins.value = ?", "E-Tapestry Id #", contact.id.to_s).references(:custom_field_masters, :custom_field_joins).first end - def contact + def contact @entry.contact end def find_or_create_supporter - supporter || contact.create_or_update_CUSTOM + supporter || contact.create_or_update_CUSTOM end end class NoteRow < RowWrapper def note - @note ||= @row['Note'] + @note ||= @row["Note"] end - + def to_supporter_note {created_at: date, content: note} end def process(user) - sn = find_or_create_supporter.supporter_notes.build(user:user, **self.to_supporter_note.except(:created_at)) - - sn.created_at = self.to_supporter_note[:created_at] + sn = find_or_create_supporter.supporter_notes.build(user: user, **to_supporter_note.except(:created_at)) + + sn.created_at = to_supporter_note[:created_at] sn.save! - @entry.journal_entries_to_items.create(item:sn) + @entry.journal_entries_to_items.create(item: sn) end end class ContactEvent < RowWrapper def note - @note ||= @row['Note'] + @note ||= @row["Note"] end - + def subject - @row['Contact Subject'] + @row["Contact Subject"] end - + def to_supporter_note {created_at: date, content: "Subject: #{subject}, Note: #{note}"} end def process(user) + sn = find_or_create_supporter.supporter_notes.build(user: user, **to_supporter_note.except(:created_at)) - sn = find_or_create_supporter.supporter_notes.build(user:user, **self.to_supporter_note.except(:created_at)) - - sn.created_at = self.to_supporter_note[:created_at] + sn.created_at = to_supporter_note[:created_at] sn.save! - @entry.journal_entries_to_items.create(item:sn) + @entry.journal_entries_to_items.create(item: sn) end end @@ -272,18 +258,16 @@ class CalendarItem < RowWrapper def to_supporter_note {created_at: date, content: "Calendar Item"} end + def process(user) + sn = find_or_create_supporter.supporter_notes.build(user: user, **to_supporter_note.except(:created_at)) - sn = find_or_create_supporter.supporter_notes.build(user:user, **self.to_supporter_note.except(:created_at)) - - sn.created_at = self.to_supporter_note[:created_at] + sn.created_at = to_supporter_note[:created_at] sn.save! - @entry.journal_entries_to_items.create(item:sn) + @entry.journal_entries_to_items.create(item: sn) end end - - class Gift < RowWrapper include ::ETapImportJournalEntry::Common::Payment include ::ETapImportJournalEntry::Common::Purchase @@ -292,15 +276,13 @@ def corresponding_payment end def process(user) - @entry.journal_entries_to_items.create(item:create_or_update_payment) + @entry.journal_entries_to_items.create(item: create_or_update_payment) end end - - - + class Pledge < RowWrapper include ::ETapImportJournalEntry::Common::Pledge - + def to_supporter_note content = "Pledged: #{pledged}" if pledge_written_off.present? @@ -310,32 +292,28 @@ def to_supporter_note end def process(user) + sn = find_or_create_supporter.supporter_notes.build(user: user, **to_supporter_note.except(:created_at)) - sn = find_or_create_supporter.supporter_notes.build(user:user, **self.to_supporter_note.except(:created_at)) - - sn.created_at = self.to_supporter_note[:created_at] + sn.created_at = to_supporter_note[:created_at] sn.save! - @entry.journal_entries_to_items.create(item:sn) + @entry.journal_entries_to_items.create(item: sn) end end - - - + class CreditPurchase < RowWrapper - include Common::Purchase include Common::Payment - + def process(user) - je_to_i= @entry.journal_entries_to_items.create(item: create_or_update_payment) + @entry.journal_entries_to_items.create(item: create_or_update_payment) end end - + class PledgePayment < RowWrapper include Common::Purchase include Common::Payment include Common::Pledge - + def to_supporter_note content = "Pledged: #{pledged}" if pledge_written_off.present? @@ -345,15 +323,12 @@ def to_supporter_note end def process(user) - je_to_i= @entry.journal_entries_to_items.create(item: create_or_update_payment) - sn = je_to_i.item.supporter.supporter_notes.build(user:user, **self.to_supporter_note.except(:created_at)) - - sn.created_at = self.to_supporter_note[:created_at] + je_to_i = @entry.journal_entries_to_items.create(item: create_or_update_payment) + sn = je_to_i.item.supporter.supporter_notes.build(user: user, **to_supporter_note.except(:created_at)) + + sn.created_at = to_supporter_note[:created_at] sn.save! - @entry.journal_entries_to_items.create(item:sn) + @entry.journal_entries_to_items.create(item: sn) end end - - - end diff --git a/app/models/email_customization.rb b/app/models/email_customization.rb index d959696b6..487993285 100644 --- a/app/models/email_customization.rb +++ b/app/models/email_customization.rb @@ -1,6 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EmailCustomization < ApplicationRecord - belongs_to :nonprofit, required: true + belongs_to :nonprofit, optional: false - validates :name, :contents, presence: true + validates :name, :contents, presence: true end diff --git a/app/models/email_list.rb b/app/models/email_list.rb index 5ef7045e5..be35a0b6b 100644 --- a/app/models/email_list.rb +++ b/app/models/email_list.rb @@ -13,7 +13,7 @@ class EmailList < ApplicationRecord # the path on the Mailchimp api for the list def list_path - "lists/#{mailchimp_list_id}" + "lists/#{mailchimp_list_id}" end def list_url @@ -37,7 +37,7 @@ def api_key # The base Mailchimp API uri. This includes getting the proper datacenter # using the api key. # - # NOTE: this value is cached. This is not an awful decision but could be + # NOTE: this value is cached. This is not an awful decision but could be # easy to forget this def base_uri @base_uri ||= Mailchimp.base_uri(api_key) @@ -67,11 +67,11 @@ def populate_list end def build_supporter_post_operation(supporter) - MailchimpBatchOperation.new(method: 'POST', list: self, supporter:supporter) + MailchimpBatchOperation.new(method: "POST", list: self, supporter: supporter) end # we don't currently use this but we could in the future def build_supporter_delete_operation(supporter) - MailchimpBatchOperation.new(method: 'DELETE', list: self, supporter:supporter) + MailchimpBatchOperation.new(method: "DELETE", list: self, supporter: supporter) end end diff --git a/app/models/email_setting.rb b/app/models/email_setting.rb index 0171f071d..07eff1821 100644 --- a/app/models/email_setting.rb +++ b/app/models/email_setting.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EmailSetting < ApplicationRecord - attr_accessible \ :user_id, :user, :nonprofit_id, :nonprofit, @@ -12,5 +11,4 @@ class EmailSetting < ApplicationRecord belongs_to :nonprofit belongs_to :user - end diff --git a/app/models/event.rb b/app/models/event.rb index 76413fecd..a979d8156 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,121 +1,118 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Event < ApplicationRecord - - attr_accessible \ - :deleted, #bool for soft-delete - :name, # str - :tagline, # str - :summary, # text - :body, # text (html) + attr_accessible \ + :deleted, # bool for soft-delete + :name, # str + :tagline, # str + :summary, # text + :body, # text (html) :end_datetime, :start_datetime, - :latitude, # float - :longitude, # float - :location, # str - :city, # str - :state_code, # str - :address, # str - :zip_code, # str - :main_image, # str - :remove_main_image, # for carrierwave - :background_image, # str - :remove_background_image, # bool carrierwave - :published, # bool - :slug, # str - :directions, # text - :venue_name, # str - :profile_id, # creator - :ticket_levels_attributes, - :show_total_raised, # bool - :show_total_count, # bool - :hide_activity_feed, # bool - :nonprofit_id, # host - :hide_title, # bool + :latitude, # float + :longitude, # float + :location, # str + :city, # str + :state_code, # str + :address, # str + :zip_code, # str + :main_image, # str + :remove_main_image, # for carrierwave + :background_image, # str + :remove_background_image, # bool carrierwave + :published, # bool + :slug, # str + :directions, # text + :venue_name, # str + :profile_id, # creator + :ticket_levels_attributes, + :show_total_raised, # bool + :show_total_count, # bool + :hide_activity_feed, # bool + :nonprofit_id, # host + :hide_title, # bool :organizer_email, # string :receipt_message, # text - :nonprofit - - validates :name, :presence => true - validates :end_datetime, :presence => true - validates :start_datetime, :presence => true - validates :address, :presence => true - validates :city, :presence => true - validates :state_code, :presence => true - validates :slug, :presence => true, uniqueness: {scope: :nonprofit_id, message: 'You already have an event with that URL'} - validates :nonprofit_id, :presence => true - validates :profile_id, :presence => true - - belongs_to :nonprofit - belongs_to :profile - has_many :donations - has_many :supporters, through: :donations - has_many :recurring_donations - has_many :ticket_levels, :dependent => :destroy - has_many :event_discounts, dependent: :destroy - has_many :tickets - has_many :payments, through: :tickets - has_many :charges, through: :tickets - has_many :ticketholders, through: :tickets, source: :supporter - has_many :roles, as: :host, dependent: :destroy - has_many :activities, as: :host, dependent: :destroy - has_one :misc_event_info - - geocoded_by :full_address - - accepts_nested_attributes_for :ticket_levels, :allow_destroy => true - - mount_uploader :main_image, EventMainImageUploader - mount_uploader :background_image, EventBackgroundImageUploader - - scope :not_deleted, -> {where(deleted: [nil,false])} - scope :deleted, -> {where(deleted: true)} - scope :published, -> {where(:published => true)} - scope :upcoming, -> {where("start_datetime >= ?", Date.today).published} - scope :past, -> {where("end_datetime < ?", Date.today).published} - scope :unpublished, -> {where("published != ?", true)} - - validates :slug, uniqueness: {scope: :nonprofit_id, message: 'You already have a campaign with that name.'} - - before_validation(on: :create) do - unless self.slug - self.slug = Format::Url.convert_to_slug(name) - end - self.published = false if self.published.nil? - self.total_raised ||= 0 + :nonprofit + + validates :name, presence: true + validates :end_datetime, presence: true + validates :start_datetime, presence: true + validates :address, presence: true + validates :city, presence: true + validates :state_code, presence: true + validates :slug, presence: true, uniqueness: {scope: :nonprofit_id, message: "You already have an event with that URL"} + validates :nonprofit_id, presence: true + validates :profile_id, presence: true + + belongs_to :nonprofit + belongs_to :profile + has_many :donations + has_many :supporters, through: :donations + has_many :recurring_donations + has_many :ticket_levels, dependent: :destroy + has_many :event_discounts, dependent: :destroy + has_many :tickets + has_many :payments, through: :tickets + has_many :charges, through: :tickets + has_many :ticketholders, through: :tickets, source: :supporter + has_many :roles, as: :host, dependent: :destroy + has_many :activities, as: :host, dependent: :destroy + has_one :misc_event_info + + geocoded_by :full_address + + accepts_nested_attributes_for :ticket_levels, allow_destroy: true + + mount_uploader :main_image, EventMainImageUploader + mount_uploader :background_image, EventBackgroundImageUploader + + scope :not_deleted, -> { where(deleted: [nil, false]) } + scope :deleted, -> { where(deleted: true) } + scope :published, -> { where(published: true) } + scope :upcoming, -> { where("start_datetime >= ?", Date.today).published } + scope :past, -> { where("end_datetime < ?", Date.today).published } + scope :unpublished, -> { where.not(published: true) } + + validates :slug, uniqueness: {scope: :nonprofit_id, message: "You already have a campaign with that name."} + + before_validation(on: :create) do + unless slug + self.slug = Format::Url.convert_to_slug(name) + end + self.published = false if published.nil? + self.total_raised ||= 0 self - end + end - after_validation :geocode + after_validation :geocode - after_create do - user = self.profile.user - Role.create(name: :event_editor, user_id: user.id, host: self) - EventMailer.delay.creation_followup(self) - self - end + after_create do + user = profile.user + Role.create(name: :event_editor, user_id: user.id, host: self) + EventMailer.delay.creation_followup(self) + self + end - def url - "#{self.nonprofit.url}/events/#{self.slug}" - end + def url + "#{nonprofit.url}/events/#{slug}" + end def full_address - Format::Address.full_address(self.address, self.city, self.state_code, self.zip_code) + Format::Address.full_address(address, city, state_code, zip_code) end - def hide_cover_fees? - nonprofit.hide_cover_fees? || misc_event_info&.hide_cover_fees_option - end + def hide_cover_fees? + nonprofit.hide_cover_fees? || misc_event_info&.hide_cover_fees_option + end - def fee_coverage_option + def fee_coverage_option @fee_coverage_option ||= misc_event_info&.fee_coverage_option_config || nonprofit.fee_coverage_option end # generally, don't use - def fee_coverage_option=(option) - @fee_coverage_option = option - end + attr_writer :fee_coverage_option - def get_tickets_button_label - misc_event_info&.custom_get_tickets_button_label || 'Get Tickets' - end + def get_tickets_button_label + misc_event_info&.custom_get_tickets_button_label || "Get Tickets" + end end diff --git a/app/models/event_discount.rb b/app/models/event_discount.rb index 8e894b14a..0143abd5f 100644 --- a/app/models/event_discount.rb +++ b/app/models/event_discount.rb @@ -1,13 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EventDiscount < ApplicationRecord - - belongs_to :event, required: true + belongs_to :event, optional: false has_many :tickets - validates_presence_of :code, :name, :percent + validates :code, :name, :percent, presence: true validates :percent, numericality: {greater_than: 0, less_than_or_equal_to: 100} - - - end diff --git a/app/models/export.rb b/app/models/export.rb index ee4717a46..19abd1794 100644 --- a/app/models/export.rb +++ b/app/models/export.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Export < ApplicationRecord - STATUS = %w[queued started completed failed].freeze attr_accessible :exception, :nonprofit, :status, :user, :export_type, :parameters, :ended, :url, :user_id, :nonprofit_id diff --git a/app/models/export_format.rb b/app/models/export_format.rb index b7e38d5a6..3b153b632 100644 --- a/app/models/export_format.rb +++ b/app/models/export_format.rb @@ -10,7 +10,7 @@ class ExportFormat < ApplicationRecord validates :name, presence: true validates :nonprofit_id, presence: true - validates_with PostgresqlDateFormatValidator, { attribute_name: :date_format } + validates_with PostgresqlDateFormatValidator, {attribute_name: :date_format} validate :valid_custom_columns_and_values? @@ -19,38 +19,38 @@ class ExportFormat < ApplicationRecord private ALLOWED_COLUMNS_TO_HAVE_NAMES_CUSTOMIZED = [ - 'payments.date', - 'payments.gross_amount', - 'payments.fee_total', - 'payments.net_amount', - 'payments.kind', - 'donations.anonymous', - 'supporters.anonymous', - 'donations.anonymous OR supporters.anonymous', - 'campaigns_for_export.name', - 'campaigns_for_export.id', - 'campaigns_for_export.creator_email', - 'campaign_gift_options.name', - 'events_for_export.name', - 'payments.id', - 'offsite_payments.check_number', - 'donations.comment', - 'misc_payment_infos.fee_covered', - 'donations.created_at' + "payments.date", + "payments.gross_amount", + "payments.fee_total", + "payments.net_amount", + "payments.kind", + "donations.anonymous", + "supporters.anonymous", + "donations.anonymous OR supporters.anonymous", + "campaigns_for_export.name", + "campaigns_for_export.id", + "campaigns_for_export.creator_email", + "campaign_gift_options.name", + "events_for_export.name", + "payments.id", + "offsite_payments.check_number", + "donations.comment", + "misc_payment_infos.fee_covered", + "donations.created_at" ].freeze ALLOWED_COLUMNS_TO_HAVE_VALUES_CUSTOMIZED = [ - 'payments.kind', - 'donations.designation', - 'donations.anonymous', - 'supporters.anonymous', - 'donations.anonymous OR supporters.anonymous', - 'donations.comment', - 'campaigns_for_export.name', - 'campaign_gift_options.name', - 'events_for_export.name', - 'donations.comment', - 'misc_payment_infos.fee_covered' + "payments.kind", + "donations.designation", + "donations.anonymous", + "supporters.anonymous", + "donations.anonymous OR supporters.anonymous", + "donations.comment", + "campaigns_for_export.name", + "campaign_gift_options.name", + "events_for_export.name", + "donations.comment", + "misc_payment_infos.fee_covered" ].freeze private_constant :ALLOWED_COLUMNS_TO_HAVE_NAMES_CUSTOMIZED @@ -60,10 +60,10 @@ def valid_custom_columns_and_values? return if custom_columns_and_values.nil? custom_columns_and_values.keys.each do |column| if ALLOWED_COLUMNS_TO_HAVE_NAMES_CUSTOMIZED.include? column - unless (custom_columns_and_values[column].include? 'custom_name') || (custom_columns_and_values[column].include? 'custom_values') + unless (custom_columns_and_values[column].include? "custom_name") || (custom_columns_and_values[column].include? "custom_values") errors.add(:custom_columns_and_values, "you need to include a 'custom_name' or 'custom_values' key to customize #{column} column") end - if (!ALLOWED_COLUMNS_TO_HAVE_VALUES_CUSTOMIZED.include? column) && (custom_columns_and_values[column].include? 'custom_values') + if (!ALLOWED_COLUMNS_TO_HAVE_VALUES_CUSTOMIZED.include? column) && (custom_columns_and_values[column].include? "custom_values") errors.add(:custom_columns_and_values, "column #{column} can't have its values customized") end else @@ -75,8 +75,8 @@ def valid_custom_columns_and_values? def normalize_custom_columns custom_columns_and_values&.each do |column, customizations| customizations&.each do |customization, customization_subject| - if customization == 'custom_name' - custom_columns_and_values[column]['custom_name'] = + if customization == "custom_name" + custom_columns_and_values[column]["custom_name"] = insert_trailing_double_quotes(customization_subject) end end diff --git a/app/models/fee_era.rb b/app/models/fee_era.rb index bf76eddc8..e7364e363 100644 --- a/app/models/fee_era.rb +++ b/app/models/fee_era.rb @@ -3,41 +3,44 @@ # FeeEra describes a period of time where a given set of fee structures apply. # # @attribute! start_time -# @return [DateTime|nil] the time where the FeeEra should begin being applied. +# @return [DateTime|nil] the time where the FeeEra should begin being applied. # If nil, the era began at the earliest possible time. (Time.at(0)). At minimum, start_time or end_time must be set. # @attribute! end_time -# @return [DateTime|nil] the time where the FeeEra should stop being applied. +# @return [DateTime|nil] the time where the FeeEra should stop being applied. # If nil, the era ends at the latest possible time, i.e. way in the future. At minimum, start_time or end_time must be set. # # @attribute! fee_structures # @return One or more FeeStructure objects that apply during the FeeEra class FeeEra < ApplicationRecord - has_one :fee_coverage_detail_base, validate: true has_many :fee_structures do def find_by_source(source) - raise ArgumentError, - 'source must be a valid Stripe::Source, Stripe::Card or similar' unless source.respond_to?(:brand) and source.respond_to?(:country) - brand_found = select {|i| i.brand == source.brand}.first + unless source.respond_to?(:brand) and source.respond_to?(:country) + raise ArgumentError, + "source must be a valid Stripe::Source, Stripe::Card or similar" + end + brand_found = select { |i| i.brand == source.brand }.first return brand_found if brand_found - - blank_source = select{|i| i.brand.blank?}.first - raise ArgumentError, - 'source must be a valid Stripe::Source, Stripe::Card or similar' if blank_source.nil? + + blank_source = select { |i| i.brand.blank? }.first + if blank_source.nil? + raise ArgumentError, + "source must be a valid Stripe::Source, Stripe::Card or similar" + end blank_source end end validates_associated :fee_structures, :fee_coverage_detail_base - + validates :international_surcharge_fee, numericality: {greater_than_or_equal_to: 0, less_than: 1}, allow_nil: true - validates_presence_of :international_surcharge_fee, if: -> { local_country.present? } - - validates_presence_of :fee_coverage_detail_base + validates :international_surcharge_fee, presence: {if: -> { local_country.present? }} + + validates :fee_coverage_detail_base, presence: true # # Should an international surcharge be added # @@ -48,21 +51,21 @@ def find_by_source(source) def charge_international_fee?(source) local_country.present? && source.country != local_country end - + # Whether the given time is included in the FeeEra. true if it does, false otherwise. # @param at [DateTime,nil] - def in_era?(at=nil) + def in_era?(at = nil) at ||= Time.current - test_start_time = start_time ||Time.at(0) - test_end_time = end_time || Time.new(9999,1) + test_start_time = start_time || Time.at(0) + test_end_time = end_time || Time.new(9999, 1) (test_start_time...test_end_time).cover? at end # Given a time, find the FeeEra that time is within. # @param at [DateTime,nil] the time to use for searching for a FeeEra. Default of for current time - def self.find_by_time(at=nil) + def self.find_by_time(at = nil) at ||= Time.current - era_result = self.all.select{|i| i.in_era?(at)} + era_result = all.select { |i| i.in_era?(at) } raise ActiveRecord::RecordNotFound if era_result.none? era_result.first end @@ -72,7 +75,7 @@ def self.find_by_time(at=nil) # 1. Is there a FeeStructure in fee_structures with the brand of source? If so, we return that FeeStructure. # 2. Return the FeeStructure in fee_structures which has no set brand. # @param [#brand,#country] a Stripe::Source, Stripe::Card or similar - # @returns [FeeStructure] + # @returns [FeeStructure] def find_fee_structure_by_source(source) fee_structures.find_by_source(source) end @@ -83,47 +86,47 @@ def find_fee_structure_by_source(source) # @option opts [Integer] :amount the amount of the transaction in cents # @option opts [Integer] :flat_fee (0) the flat platform fee to add to the given fee structure - def calculate_fee(opts={}) + def calculate_fee(opts = {}) find_fee_structure_by_source(opts[:source]).calculate_fee(opts) end # @param [Hash] opts # @option opts [#brand] :source the source to use for calculating the fee # @option opts [Integer] :amount the amount of the transaction in cents - def calculate_stripe_fee(opts={}) + def calculate_stripe_fee(opts = {}) find_fee_structure_by_source(opts[:source]).calculate_stripe_fee(opts) end # @param [Hash] opts # @option opts [Stripe::Charge] :charge the Stripe::Charge to use for calculating the fee - # @option opts [Stripe::Refund] :refund the Stripe::Refund for + # @option opts [Stripe::Refund] :refund the Stripe::Refund for # @option opts [Stripe::ApplicationFee] :application_fee the Stripe::ApplicationFee for this Charge - def calculate_application_fee_refund(opts={}) + def calculate_application_fee_refund(opts = {}) application_fee = opts[:application_fee] charge = opts[:charge] refund = opts[:refund] stripe_fee_to_reserve = refund_stripe_fee? ? 0 : calculate_stripe_fee(amount: charge.amount, source: charge.source) max_fee_to_refund = application_fee.amount - stripe_fee_to_reserve refundable_fee_left = max_fee_to_refund - application_fee.amount_refunded - if (refundable_fee_left <= 0) + if refundable_fee_left <= 0 return 0 end - if (charge.refunded) - return refundable_fee_left + if charge.refunded + refundable_fee_left else portion_of_charge_refunded = BigDecimal(refund.amount) / BigDecimal(charge.amount) amount_to_refund = (BigDecimal(max_fee_to_refund) * portion_of_charge_refunded).floor - amount_to_refund >= refundable_fee_left ? refundable_fee_left : amount_to_refund + (amount_to_refund >= refundable_fee_left) ? refundable_fee_left : amount_to_refund end end - + # @param [Hash] opts # @option opts [Time] :charge_date the date that the charge occurred for purposes of finding the correct fee era # @option opts [Stripe::Charge] :charge the Stripe::Charge to use for calculating the fee - # @option opts [Stripe::Refund] :refund the Stripe::Refund for + # @option opts [Stripe::Refund] :refund the Stripe::Refund for # @option opts [Stripe::ApplicationFee] :application_fee the Stripe::ApplicationFee for this Charge - def self.calculate_application_fee_refund(opts={}) + def self.calculate_application_fee_refund(opts = {}) FeeEra.find_by_time(opts[:charge_date]).calculate_application_fee_refund(opts) end @@ -133,7 +136,7 @@ def self.calculate_application_fee_refund(opts={}) # @option opts [Integer] :amount the amount of the transaction in cents # @option opts [Integer] :flat_fee (0) the flat platform fee to add to the given fee structure # @option opts [DateTime,nil] :at (nil) the time to use for searching for a FeeEra. Default of current time - def self.calculate_fee(opts={}) + def self.calculate_fee(opts = {}) FeeEra.find_by_time(opts[:at]).calculate_fee(opts) end @@ -141,11 +144,11 @@ def self.calculate_fee(opts={}) # @option opts [#brand, #country] :source the source to use for calculating the fee # @option opts [Integer] :amount the amount of the transaction in cents # @option opts [DateTime,nil] :at (nil) the time to use for searching for a FeeEra. Default of current time - def self.calculate_stripe_fee(opts={}) + def self.calculate_stripe_fee(opts = {}) FeeEra.find_by_time(opts[:at]).calculate_stripe_fee(opts) end def self.current FeeEra.find_by_time end -end \ No newline at end of file +end diff --git a/app/models/fee_structure.rb b/app/models/fee_structure.rb index 01623a809..dfd7d87e8 100644 --- a/app/models/fee_structure.rb +++ b/app/models/fee_structure.rb @@ -1,17 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # -# A FeeStructure summarizes a set of various Stripe rates and surcharges to use when applied to a card and a transaction. +# A FeeStructure summarizes a set of various Stripe rates and surcharges to use when applied to a card and a transaction. # # !@attribute brand # @return [String,nil] the card brands to apply to cards to if this is the most specific brand provider in the set of FeeStructures for a FeeEra. -# If this is nil, this is the least specific FeeStructure. +# If this is nil, this is the least specific FeeStructure. # # !@attribute stripe_fee # @return [BigNumber] the base stripe percentage fee that should apply to charges using the FeeStructure # # !@attribute flat_fee # @return [Integer] the flat fee in cents which should be applied to charges using this FeeStructure -# +# # !@attribute [r] international_surcharge_fee # @return [BigDecimal] the additional percentage which should apply to charges for cards which are not in local_country @@ -19,14 +19,14 @@ class FeeStructure < ApplicationRecord belongs_to :fee_era validates :flat_fee, - numericality: {only_integer: true, greater_than_or_equal_to: 0}, + numericality: {only_integer: true, greater_than_or_equal_to: 0}, presence: true validates :stripe_fee, numericality: {greater_than_or_equal_to: 0, less_than: 1}, presence: true - validates_presence_of :fee_era + validates :fee_era, presence: true delegate :charge_international_fee?, :international_surcharge_fee, to: :fee_era @@ -36,15 +36,15 @@ class FeeStructure < ApplicationRecord # @option opts [Integer] :amount the amount of the transaction in cents # @option opts [Integer] :flat_fee (0) the flat platform fee to add to the given fee structure - def calculate_fee(opts={}) - FeeCalculation.calculate(opts.merge(fee_structure:self)) + def calculate_fee(opts = {}) + FeeCalculation.calculate(opts.merge(fee_structure: self)) end # @param [Hash] opts # @option opts [#brand] :source the source to use for calculating the fee # @option opts [Integer] :amount the amount of the transaction in cents - def calculate_stripe_fee(opts={}) - StripeFeeCalculation.calculate(opts.merge(fee_structure:self)) + def calculate_stripe_fee(opts = {}) + StripeFeeCalculation.calculate(opts.merge(fee_structure: self)) end class FeeCalculation @@ -52,11 +52,11 @@ class FeeCalculation attr_accessor :source, :platform_fee, :flat_fee, :amount, :fee_structure validates :source, :platform_fee, :amount, presence: true - validates_numericality_of :platform_fee, less_than: 1.0, greater_than_or_equal_to: 0.0 - validates_numericality_of :amount, greater_than: 0, is_integer: true + validates :platform_fee, numericality: {less_than: 1.0, greater_than_or_equal_to: 0.0} + validates :amount, numericality: {greater_than: 0, is_integer: true} validate :validate_source_is_source_like - def initialize(args={}) + def initialize(args = {}) @platform_fee = args[:platform_fee] @source = args[:source] @flat_fee = args[:flat_fee] || 0 @@ -66,7 +66,7 @@ def initialize(args={}) def calculate raise ArgumentError.new(errors.full_messages) unless valid? - + fee_surcharge = fee_structure.stripe_fee + BigDecimal(platform_fee) if fee_structure.charge_international_fee?(source) fee_surcharge += fee_structure.international_surcharge_fee @@ -75,15 +75,15 @@ def calculate (BigDecimal(amount) * fee_surcharge).ceil + fee_structure.flat_fee + flat_fee end - def self.calculate(args={}) + def self.calculate(args = {}) FeeCalculation.new(args).calculate end private def validate_source_is_source_like - errors.add(:source, 'must respond to #brand') unless source.respond_to?(:brand) - errors.add(:source, 'must respond to #country') unless source.respond_to?(:country) + errors.add(:source, "must respond to #brand") unless source.respond_to?(:brand) + errors.add(:source, "must respond to #country") unless source.respond_to?(:country) end end @@ -92,15 +92,15 @@ class StripeFeeCalculation attr_accessor :source, :amount, :fee_structure validates :source, :amount, :fee_structure, presence: true - validates_numericality_of :amount, greater_than: 0, is_integer: true + validates :amount, numericality: {greater_than: 0, is_integer: true} validate :validate_source_is_source_like - def initialize(args={}) + def initialize(args = {}) @source = args[:source] @amount = args[:amount] @fee_structure = args[:fee_structure] end - + def calculate raise ArgumentError.new(errors.full_messages) unless valid? fee_surcharge = fee_structure.stripe_fee @@ -111,15 +111,15 @@ def calculate (BigDecimal(amount) * fee_surcharge).ceil + fee_structure.flat_fee end - def self.calculate(args={}) + def self.calculate(args = {}) StripeFeeCalculation.new(args).calculate end private def validate_source_is_source_like - errors.add(:source, 'must respond to #brand') unless source.respond_to?(:brand) - errors.add(:source, 'must respond to #country') unless source.respond_to?(:country) + errors.add(:source, "must respond to #brand") unless source.respond_to?(:brand) + errors.add(:source, "must respond to #country") unless source.respond_to?(:country) end end end diff --git a/app/models/full_contact_info.rb b/app/models/full_contact_info.rb index 19c71e09f..39df05601 100644 --- a/app/models/full_contact_info.rb +++ b/app/models/full_contact_info.rb @@ -1,23 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class FullContactInfo < ApplicationRecord - attr_accessible \ - :email, - :full_name, - :gender, - :city, - :county, - :state_code, - :country, - :continent, - :age, - :age_range, + attr_accessible \ + :email, + :full_name, + :gender, + :city, + :county, + :state_code, + :country, + :continent, + :age, + :age_range, :location_general, :supporter_id, :supporter, :websites - has_many :full_contact_photos, dependent: :destroy - has_many :full_contact_social_profiles, dependent: :destroy - has_many :full_contact_orgs, dependent: :destroy - has_many :full_contact_topics, dependent: :destroy + has_many :full_contact_photos, dependent: :destroy + has_many :full_contact_social_profiles, dependent: :destroy + has_many :full_contact_orgs, dependent: :destroy + has_many :full_contact_topics, dependent: :destroy belongs_to :supporter end diff --git a/app/models/full_contact_org.rb b/app/models/full_contact_org.rb index 05acfc9c8..c6c423814 100644 --- a/app/models/full_contact_org.rb +++ b/app/models/full_contact_org.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class FullContactOrg < ApplicationRecord - - attr_accessible \ + attr_accessible \ :name, :is_primary, :name, @@ -12,5 +11,4 @@ class FullContactOrg < ApplicationRecord :full_contact_info_id, :full_contact_info belongs_to :full_contact_info - end diff --git a/app/models/full_contact_photo.rb b/app/models/full_contact_photo.rb index b96a5bb7e..1326d07fb 100644 --- a/app/models/full_contact_photo.rb +++ b/app/models/full_contact_photo.rb @@ -1,13 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class FullContactPhoto < ApplicationRecord - attr_accessible \ - :full_contact_info, - :full_contact_info_id, - :type_id, # i.e. twitter, linkedin, facebook - :is_primary, #bool - :url #string + attr_accessible \ + :full_contact_info, + :full_contact_info_id, + :type_id, # i.e. twitter, linkedin, facebook + :is_primary, # bool + :url # string - belongs_to :full_contact_info + belongs_to :full_contact_info - validates_presence_of :full_contact_info -end \ No newline at end of file + validates :full_contact_info, presence: true +end diff --git a/app/models/full_contact_social_profile.rb b/app/models/full_contact_social_profile.rb index b98a4dd34..f9a00dc0b 100644 --- a/app/models/full_contact_social_profile.rb +++ b/app/models/full_contact_social_profile.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class FullContactSocialProfile < ApplicationRecord - attr_accessible \ - :full_contact_info, - :full_contact_info_id, - :type_id, # i.e. twitter, linkedin, facebook - :username, #string - :uid, # string - :bio, #string - :url #string + attr_accessible \ + :full_contact_info, + :full_contact_info_id, + :type_id, # i.e. twitter, linkedin, facebook + :username, # string + :uid, # string + :bio, # string + :url # string - belongs_to :full_contact_info + belongs_to :full_contact_info - validates_presence_of :full_contact_info -end \ No newline at end of file + validates :full_contact_info, presence: true +end diff --git a/app/models/full_contact_topic.rb b/app/models/full_contact_topic.rb index 0839097bc..ed5ef6c57 100644 --- a/app/models/full_contact_topic.rb +++ b/app/models/full_contact_topic.rb @@ -1,11 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class FullContactTopic < ApplicationRecord - - attr_accessible \ + attr_accessible \ :provider, :value, :full_contact_info_id, :full_contact_info belongs_to :full_contact_info - end diff --git a/app/models/image_attachment.rb b/app/models/image_attachment.rb index 642ba68c1..b6f9bb399 100644 --- a/app/models/image_attachment.rb +++ b/app/models/image_attachment.rb @@ -1,10 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class ImageAttachment < ApplicationRecord + attr_accessible :parent_id, :file + mount_uploader :file, ImageAttachmentUploader - attr_accessible :parent_id, :file - mount_uploader :file, ImageAttachmentUploader - - # not sure if poly parent is used on this model, as all values are nil in db - belongs_to :parent, :polymorphic => true - + # not sure if poly parent is used on this model, as all values are nil in db + belongs_to :parent, polymorphic: true end diff --git a/app/models/import.rb b/app/models/import.rb index 66a06071a..ad8fc33b1 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -1,19 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Import < ApplicationRecord + attr_accessible \ + :user_id, :user, + :email, # email of the user who ma + :nonprofit_id, :nonprofit, + :row_count, + :imported_count, + :date - attr_accessible \ - :user_id, :user, - :email, # email of the user who ma - :nonprofit_id, :nonprofit, - :row_count, - :imported_count, - :date - - has_many :supporters - belongs_to :nonprofit - belongs_to :user - - validates :user, presence: true + has_many :supporters + belongs_to :nonprofit + belongs_to :user + validates :user, presence: true end - diff --git a/app/models/journal_entries_to_item.rb b/app/models/journal_entries_to_item.rb index 2c69cbb45..462697bc5 100644 --- a/app/models/journal_entries_to_item.rb +++ b/app/models/journal_entries_to_item.rb @@ -2,4 +2,4 @@ class JournalEntriesToItem < ApplicationRecord attr_accessible :item belongs_to :e_tap_import_journal_entry belongs_to :item, polymorphic: true -end \ No newline at end of file +end diff --git a/app/models/mailchimp_batch_operation.rb b/app/models/mailchimp_batch_operation.rb index defe1d4e5..fb6e21115 100644 --- a/app/models/mailchimp_batch_operation.rb +++ b/app/models/mailchimp_batch_operation.rb @@ -4,7 +4,7 @@ # See more at: https://mailchimp.com/developer/marketing/api/list-members/ class MailchimpBatchOperation include ActiveModel::Model - + attr_accessor :method, # POST or DELETE :list, # the EmailList you're applying this to :supporter # the Supporter in question @@ -14,24 +14,22 @@ def email end def body - method === "POST" ? Mailchimp::create_subscribe_body(supporter) : nil + (method === "POST") ? Mailchimp.create_subscribe_body(supporter) : nil end def path path = list.list_members_path - path = path + "/#{Digest::MD5.hexdigest(email.downcase).to_s}" if method === "DELETE" + path += "/#{Digest::MD5.hexdigest(email.downcase)}" if method === "DELETE" path end def to_h - if (email) + if email result = {method: method, path: path} if body - result[:body] = JSON::dump(body) + result[:body] = JSON.dump(body) end result - else - nil end end end diff --git a/app/models/manual_balance_adjustment.rb b/app/models/manual_balance_adjustment.rb index c41c299eb..fe9295efb 100644 --- a/app/models/manual_balance_adjustment.rb +++ b/app/models/manual_balance_adjustment.rb @@ -3,18 +3,18 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class ManualBalanceAdjustment < ApplicationRecord - belongs_to :entity, polymorphic: true, required:true - belongs_to :payment, required:true + belongs_to :entity, polymorphic: true, optional: false + belongs_to :payment, optional: false has_one :supporter, through: :payment has_one :nonprofit, through: :payment - validates_presence_of :gross_amount, :fee_total, :net_amount + validates :gross_amount, :fee_total, :net_amount, presence: true before_validation :add_payment, on: :create - scope :not_disbursed, ->{where(disbursed: [nil, false])} - scope :disbursed, ->{where(disbursed: [true])} - + scope :not_disbursed, -> { where(disbursed: [nil, false]) } + scope :disbursed, -> { where(disbursed: [true]) } + def gross_amount=(gross_amount) write_attribute(:gross_amount, gross_amount) calculate_net @@ -26,20 +26,19 @@ def fee_total=(fee_total) end private + def calculate_net - self.net_amount = (gross_amount || 0) + (fee_total || 0) + self.net_amount = (gross_amount || 0) + (fee_total || 0) end - def add_payment - unless self.payment - if self.entity - build_payment(supporter:self.entity.supporter, nonprofit: self.entity.nonprofit, kind: "ManualAdjustment", - gross_amount: self.gross_amount || 0, - fee_total: self.fee_total || 0, - net_amount: self.net_amount, - date: Time.current - ) + unless payment + if entity + build_payment(supporter: entity.supporter, nonprofit: entity.nonprofit, kind: "ManualAdjustment", + gross_amount: gross_amount || 0, + fee_total: fee_total || 0, + net_amount: net_amount, + date: Time.current) end end end diff --git a/app/models/misc_campaign_info.rb b/app/models/misc_campaign_info.rb index 6b4bd0121..b7e8ce30f 100644 --- a/app/models/misc_campaign_info.rb +++ b/app/models/misc_campaign_info.rb @@ -2,7 +2,7 @@ class MiscCampaignInfo < ApplicationRecord belongs_to :campaign - validates_inclusion_of :fee_coverage_option_config, in: ['auto', 'manual', 'none', nil] + validates :fee_coverage_option_config, inclusion: {in: ["auto", "manual", "none", nil]} attr_accessible :manual_cover_fees, :paused end diff --git a/app/models/miscellaneous_np_info.rb b/app/models/miscellaneous_np_info.rb index a9df57519..cb86fddcb 100644 --- a/app/models/miscellaneous_np_info.rb +++ b/app/models/miscellaneous_np_info.rb @@ -1,12 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class MiscellaneousNpInfo < ApplicationRecord - attr_accessible \ - :donate_again_url, - :change_amount_message, - :hide_cover_fees + :donate_again_url, + :change_amount_message, + :hide_cover_fees belongs_to :nonprofit - - validates_inclusion_of :fee_coverage_option_config, in: ['auto', 'manual', 'none', nil] + + validates :fee_coverage_option_config, inclusion: {in: ["auto", "manual", "none", nil]} end diff --git a/app/models/model_extensions/payments_extension.rb b/app/models/model_extensions/payments_extension.rb index a78d97a8e..7ae99cf0a 100644 --- a/app/models/model_extensions/payments_extension.rb +++ b/app/models/model_extensions/payments_extension.rb @@ -25,12 +25,11 @@ def fee_total # orders payments without using SQL. Use this if you need them ordered # but the payments haven't been saved yet. def ordered - sort_by {|i| [i.legacy_payment.date, i.updated_at]}.reverse + sort_by { |i| [i.legacy_payment.date, i.updated_at] }.reverse end def owner proxy_association.owner end - end -end \ No newline at end of file +end diff --git a/app/models/model_extensions/transaction_assignment/refund_extension.rb b/app/models/model_extensions/transaction_assignment/refund_extension.rb index cb3d3cffc..d5f2bcb6e 100644 --- a/app/models/model_extensions/transaction_assignment/refund_extension.rb +++ b/app/models/model_extensions/transaction_assignment/refund_extension.rb @@ -13,8 +13,8 @@ def assignments # Handle a completed refund from a legacy Refund object def process_refund(refund) - donation = assignments.select{|i| i.assignable.is_a? ModernDonation}.first.assignable + donation = assignments.select { |i| i.assignable.is_a? ModernDonation }.first.assignable donation.amount = trx.amount donation.save! end -end \ No newline at end of file +end diff --git a/app/models/modern_donation.rb b/app/models/modern_donation.rb index 5716e323f..cfc6a5793 100644 --- a/app/models/modern_donation.rb +++ b/app/models/modern_donation.rb @@ -10,38 +10,36 @@ class ModernDonation < ApplicationRecord include Model::TrxAssignable setup_houid :don, :houid - # TODO must associate with events and campaigns somehow - - # NOTE: REMEMBER a Donation does not necessarily represent a single event. It could represent info - # about a recurring donation as well. No, this isn't great. - belongs_to :legacy_donation, class_name: 'Donation', foreign_key: :donation_id - - delegate :designation, :dedication, :comment, to: :legacy_donation - - as_money :amount - - def dedication - begin - JSON::parse legacy_donation.dedication - rescue - nil - end - end - - # REMEMBER: multiple ModernDonations could have the same legacy_id - def legacy_id - legacy_donation.id - end - - def publish_created - object_events.create( event_type: 'donation.created') - end - - def publish_updated - object_events.create( event_type: 'donation.updated') - end - - def publish_deleted - object_events.create( event_type: 'donation.deleted') - end + # TODO must associate with events and campaigns somehow + + # NOTE: REMEMBER a Donation does not necessarily represent a single event. It could represent info + # about a recurring donation as well. No, this isn't great. + belongs_to :legacy_donation, class_name: "Donation", foreign_key: :donation_id + + delegate :designation, :dedication, :comment, to: :legacy_donation + + as_money :amount + + def dedication + JSON.parse legacy_donation.dedication + rescue + nil + end + + # REMEMBER: multiple ModernDonations could have the same legacy_id + def legacy_id + legacy_donation.id + end + + def publish_created + object_events.create(event_type: "donation.created") + end + + def publish_updated + object_events.create(event_type: "donation.updated") + end + + def publish_deleted + object_events.create(event_type: "donation.deleted") + end end diff --git a/app/models/nonprofit.rb b/app/models/nonprofit.rb index 683409b75..325410fa3 100755 --- a/app/models/nonprofit.rb +++ b/app/models/nonprofit.rb @@ -14,7 +14,7 @@ class Nonprofit < ApplicationRecord :phone, # str: public org contact phone :main_image, # str: url of featured image - first image in profile carousel :background_image, # str: url of large profile background - :remove_background_image, #bool carrierwave + :remove_background_image, # bool carrierwave :logo, # str: small logo image url for searching :zip_code, # int :website, # str: their own website url @@ -25,8 +25,8 @@ class Nonprofit < ApplicationRecord :statement, # str: bank statement for donations towards the nonprofit :city, # str :slug, # str - :city_slug, #str - :state_code_slug, #str + :city_slug, # str + :state_code_slug, # str :ein, # str: employee identification number :published, # boolean; whether to display this profile :vetted, # bool: Whether a super admin (one of CommitChange's employees) have approved this org @@ -39,15 +39,15 @@ class Nonprofit < ApplicationRecord :referrer, # str :no_anon, # bool: whether to allow anonymous donations :roles_attributes, - :brand_font, #string (lowercase key eg. 'helvetica') - :brand_color, #string (hex color value) + :brand_font, # string (lowercase key eg. 'helvetica') + :brand_color, # string (hex color value) :hide_activity_feed, # bool :tracking_script, - :facebook, #string (url) - :twitter, #string (url) - :youtube, #string (url) - :instagram, #string (url) - :blog, #string (url) + :facebook, # string (url) + :twitter, # string (url) + :youtube, # string (url) + :instagram, # string (url) + :blog, # string (url) :card_failure_message_top, # text :card_failure_message_bottom, # text :autocomplete_supporter_address # boolean @@ -60,27 +60,27 @@ class Nonprofit < ApplicationRecord has_many :recurring_donations has_many :payments do def pending - joins(:charges).where('charges.status = ?', 'pending') + joins(:charges).where("charges.status = ?", "pending") end def pending_totals net, gross = pending.pluck(Arel.sql('SUM("payments"."net_amount") AS net, SUM("payments"."gross_amount") AS gross')).first - {'net' => net, 'gross' => gross} + {"net" => net, "gross" => gross} end def during_np_year(year) proxy_association.owner.use_zone do - where('payments.date >= ? and payments.date < ?', Time.zone.local(year), Time.zone.local(year + 1)) + where("payments.date >= ? and payments.date < ?", Time.zone.local(year), Time.zone.local(year + 1)) end end def prior_to_np_year(year) proxy_association.owner.use_zone do - where('date < ?', Time.zone.local(year)) + where("date < ?", Time.zone.local(year)) end end end - + has_many :supporters, dependent: :destroy do def dupes_on_email(strict_mode = true) QuerySupporters.dupes_on_email(proxy_association.owner.id, strict_mode) @@ -126,7 +126,7 @@ def dupes_on_last_name_and_address_and_email QuerySupporters.dupes_on_last_name_and_address_and_email(proxy_association.owner.id) end - def for_export_enumerable(query, chunk_limit=15000) + def for_export_enumerable(query, chunk_limit = 15000) QuerySupporters.for_export_enumerable(proxy_association.owner.id, query, chunk_limit) end end @@ -136,20 +136,20 @@ def for_export_enumerable(query, chunk_limit=15000) has_many :campaigns, dependent: :destroy has_many :events, dependent: :destroy has_many :tickets, through: :events - has_many :roles, as: :host, dependent: :destroy + has_many :roles, as: :host, dependent: :destroy has_many :users, through: :roles has_many :tag_masters, dependent: :destroy has_many :custom_field_masters, dependent: :destroy - has_many :activities, as: :host, dependent: :destroy + has_many :activities, as: :host, dependent: :destroy has_many :imports has_many :email_settings has_many :cards, as: :holder - has_many :supporter_cards, through: :supporters, source: :cards, class_name: 'Card' + has_many :supporter_cards, through: :supporters, source: :cards, class_name: "Card" has_many :periodic_reports has_many :export_formats has_one :nonprofit_key - + has_many :email_lists has_one :bank_account, -> { where("COALESCE(bank_accounts.deleted, false) = false") }, dependent: :destroy @@ -161,18 +161,18 @@ def for_export_enumerable(query, chunk_limit=15000) has_many :email_customizations - has_many :associated_object_events, class_name: 'ObjectEvent' + has_many :associated_object_events, class_name: "ObjectEvent" validates :name, presence: true validates :city, presence: true validates :state_code, presence: true - validates :email, format: { with: Email::Regex }, allow_blank: true + validates :email, format: {with: Email::Regex}, allow_blank: true validate :timezone_is_valid - validates_uniqueness_of :slug, scope: [:city_slug, :state_code_slug] - validates_presence_of :slug + validates :slug, uniqueness: {scope: [:city_slug, :state_code_slug]} + validates :slug, presence: true - scope :vetted, -> {where(vetted: true)} - scope :published, -> {where(published: true)} + scope :vetted, -> { where(vetted: true) } + scope :published, -> { where(published: true) } mount_uploader :main_image, NonprofitUploader mount_uploader :background_image, NonprofitBackgroundUploader @@ -180,11 +180,8 @@ def for_export_enumerable(query, chunk_limit=15000) geocoded_by :full_address - - - before_validation(on: :create) do - self.set_slugs + set_slugs self end @@ -195,7 +192,7 @@ def for_export_enumerable(query, chunk_limit=15000) included do # When you use a routing helper like `api_new_nonprofit_supporter``, you need to provide objects which have a `#to_param` # method. By default that's set to the value of `#id`. In our case, for the api objects, we want the id to instead be - # the value of `#houid`. We can't override `to_param` though because we may use route helpers which expect `#to_param` to + # the value of `#houid`. We can't override `to_param` though because we may use route helpers which expect `#to_param` to # return the value of `#id`. This is the hacky workaround. def to_modern_param ModernParams.new(houid) @@ -205,14 +202,13 @@ def to_modern_param # Register (create) a nonprofit with an initial admin def self.register(user, params) - np = self.create ConstructNonprofit.construct(user, params) - role = Role.create(user: user, name: 'nonprofit_admin', host: np) if np.valid? - return np + np = create ConstructNonprofit.construct(user, params) + Role.create(user: user, name: "nonprofit_admin", host: np) if np.valid? + np end - def nonprofit_personnel_emails - self.roles.nonprofit_personnel.joins(:user).pluck('users.email') + roles.nonprofit_personnel.joins(:user).pluck("users.email") end def total_recurring @@ -220,35 +216,35 @@ def total_recurring end def as_json(options = {}) - h = super(options) - h[:url] = self.url + h = super + h[:url] = url h end def url - "/#{self.state_code_slug}/#{self.city_slug}/#{self.slug}" + "/#{state_code_slug}/#{city_slug}/#{slug}" end def set_slugs - unless (self.slug) - self.slug = Format::Url.convert_to_slug self.name + unless slug + self.slug = Format::Url.convert_to_slug name end - unless (self.city_slug) - self.city_slug = Format::Url.convert_to_slug self.city + unless city_slug + self.city_slug = Format::Url.convert_to_slug city end - unless (self.state_code_slug) - self.state_code_slug = Format::Url.convert_to_slug self.state_code + unless state_code_slug + self.state_code_slug = Format::Url.convert_to_slug state_code end self end def full_address - Format::Address.full_address(self.address, self.city, self.state_code) + Format::Address.full_address(address, city, state_code) end def total_raised - QueryPayments.get_payout_totals( QueryPayments.ids_for_payout(self.id))['net_amount'] + QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(id))["net_amount"] end def admins @@ -260,17 +256,17 @@ def associates end def can_make_payouts? - !!(vetted && bank_account && + !!(vetted && bank_account && !bank_account.deleted && - !bank_account.pending_verification && - stripe_account&.payouts_enabled && - !(nonprofit_deactivation&.deactivated)) + !bank_account.pending_verification && + stripe_account&.payouts_enabled && + !nonprofit_deactivation&.deactivated) end def can_process_charge? - !!(vetted && - stripe_account&.charges_enabled && - !(nonprofit_deactivation&.deactivated)) + !!(vetted && + stripe_account&.charges_enabled && + !nonprofit_deactivation&.deactivated) end def active_cards @@ -283,7 +279,7 @@ def active_card=(card) raise ArgumentError.new "Pass a card to active_card or else" end Card.transaction do - active_cards.update_all :inactive => true + active_cards.update_all inactive: true return cards << card end end @@ -293,43 +289,41 @@ def active_card end def create_active_card(card_data) - if (card_data[:inactive]) + if card_data[:inactive] raise ArgumentError.new "This method is for creating active cards only" end - active_cards.update_all :inactive => true - return cards.create(card_data) + active_cards.update_all inactive: true + cards.create(card_data) end def currency_symbol - Settings.intntl.all_currencies.find{|i| i.abbv.downcase == currency.downcase}&.symbol + Settings.intntl.all_currencies.find { |i| i.abbv.downcase == currency.downcase }&.symbol end def steps_to_payout ret = [] - - ret.push({name: :verification, - status: stripe_account&.verification_status || - :unverified}) - bank_status = nil + ret.push({name: :verification, + status: stripe_account&.verification_status || + :unverified}) no_bank_account = !bank_account || bank_account.deleted pending_bank_account = bank_account&.pending_verification - valid_bank_account = bank_account && bank_account.pending_verification + bank_account && bank_account.pending_verification - if (no_bank_account) - bank_status= :no_bank_account - elsif(pending_bank_account) - bank_status=:pending_bank_account + bank_status = if no_bank_account + :no_bank_account + elsif pending_bank_account + :pending_bank_account else - bank_status=:valid_bank_account + :valid_bank_account end - + ret.push({name: :bank_account, status: bank_status}) ret.push({ - name: :vetted, + name: :vetted, status: vetted }) ret @@ -340,41 +334,39 @@ def autocomplete_supporter_address? end concerning :FeeCalculation do - # @param [Hash] opts # @option opts [#brand, #country] :source the source to use for calculating the fee # @option opts [Integer] :amount the amount of the transaction in cents # @option opts [DateTime,nil] :at (nil) the time to use for searching for a FeeEra. Default of current time - def calculate_fee(opts={}) + def calculate_fee(opts = {}) FeeEra.calculate_fee( **opts, platform_fee: billing_plan.percentage_fee.to_s, flat_fee: billing_plan.flat_fee - ) + ) end - # @param [Hash] opts # @option opts [#brand, #country] :source the source to use for calculating the fee # @option opts [Integer] :amount the amount of the transaction in cents # @option opts [DateTime,nil] :at (nil) the time to use for searching for a FeeEra. Default of current time - def calculate_stripe_fee(opts={}) + def calculate_stripe_fee(opts = {}) FeeEra.calculate_stripe_fee(opts) end # @param [Hash] opts # @option opts [Time] :charge_date the date that the charge occurred for purposes of finding the correct fee era # @option opts [Stripe::Charge] :charge the Stripe::Charge to use for calculating the fee - # @option opts [Stripe::Refund] :refund the Stripe::Refund for + # @option opts [Stripe::Refund] :refund the Stripe::Refund for # @option opts [Stripe::ApplicationFee] :application_fee the Stripe::ApplicationFee for this Charge - def calculate_application_fee_refund(opts={}) + def calculate_application_fee_refund(opts = {}) FeeEra.calculate_application_fee_refund(opts) end # the flat_fee and percentage_fee to use for calculating fee coverage on transactions for this nonprofit - # + # # These fee_coverage details are calcuated as follows: - # + # # { # flat_fee: flat_fee as part of BillingPlan (unless FeeCoverageDetailsBase.dont_consider_billing_plan is true) + flat_fee from FeeCoverageDetailBase on current FeeEra, # percentage_fee: percentage_fee as part of BillingPlan (unless FeeCoverageDetailsBase.dont_consider_billing_plan is true) + percentage_fee from FeeCoverageDetailBase on current FeeEra @@ -383,7 +375,7 @@ def fee_coverage_details return fee_coverage_details_no_billing_plan if !billing_plan { flat_fee: (FeeEra.current.fee_coverage_detail_base.dont_consider_billing_plan ? 0 : billing_plan.flat_fee) + FeeEra.current.fee_coverage_detail_base.flat_fee, - percentage_fee: (FeeEra.current.fee_coverage_detail_base.dont_consider_billing_plan ? 0: billing_plan.percentage_fee) + FeeEra.current.fee_coverage_detail_base.percentage_fee + percentage_fee: (FeeEra.current.fee_coverage_detail_base.dont_consider_billing_plan ? 0 : billing_plan.percentage_fee) + FeeEra.current.fee_coverage_detail_base.percentage_fee } end @@ -395,7 +387,7 @@ def fee_coverage_details_no_billing_plan end def fee_coverage_details_with_json_safe_keys - fee_coverage_details.transform_keys{|i| i.to_s.camelize(:lower)} + fee_coverage_details.transform_keys { |i| i.to_s.camelize(:lower) } end end @@ -403,12 +395,12 @@ def fee_coverage_details_with_json_safe_keys included do define_model_callbacks :deactivate - scope :activated, -> { includes(:nonprofit_deactivation).where('nonprofit_deactivations.nonprofit_id IS NULL OR NOT COALESCE(nonprofit_deactivations.deactivated, false)').references(:nonprofit_deactivations)} - scope :deactivated, -> { joins(:nonprofit_deactivation).where('nonprofit_deactivations.deactivated = true')} + scope :activated, -> { includes(:nonprofit_deactivation).where("nonprofit_deactivations.nonprofit_id IS NULL OR NOT COALESCE(nonprofit_deactivations.deactivated, false)").references(:nonprofit_deactivations) } + scope :deactivated, -> { joins(:nonprofit_deactivation).where("nonprofit_deactivations.deactivated = true") } end # Deactivate a nonprofit def deactivate! - transaction do + transaction do run_callbacks :deactivate do self.nonprofit_deactivation ||= NonprofitDeactivation.new self.nonprofit_deactivation.deactivated = true @@ -428,13 +420,13 @@ def activated? concerning :Publishing do include Nonprofit::Deactivation - included do + included do before_deactivate :unpublish! end def unpublish! self.published = false - self.save! + save! end end @@ -468,25 +460,23 @@ def hide_cover_fees? end def fee_coverage_option - @fee_coverage_option ||= miscellaneous_np_info&.fee_coverage_option_config || 'auto' + @fee_coverage_option ||= miscellaneous_np_info&.fee_coverage_option_config || "auto" end # generally, don't use - def fee_coverage_option=(option) - @fee_coverage_option = option - end + attr_writer :fee_coverage_option concerning :PathCaching do included do after_save do - self.clear_cache + clear_cache self end end class_methods do def clear_caching(id, state_code, city, name) - Rails.cache.delete(Nonprofit::create_cache_key_for_id(id)) - Rails.cache.delete(Nonprofit::create_cache_key_for_location(state_code, city, name)) + Rails.cache.delete(Nonprofit.create_cache_key_for_id(id)) + Rails.cache.delete(Nonprofit.create_cache_key_for_location(state_code, city, name)) BillingSubscription.clear_cache(id) BillingPlan.clear_cache(id) end @@ -501,7 +491,7 @@ def find_via_cached_id(id) def find_via_cached_key_for_location(state_code, city, name) key = create_cache_key_for_location(state_code, city, name) Rails.cache.fetch(key, expires_in: 4.hours) do - Nonprofit.where(:state_code_slug => state_code, :city_slug => city, :slug => name).last + Nonprofit.where(state_code_slug: state_code, city_slug: city, slug: name).last end end @@ -509,34 +499,34 @@ def create_cache_key_for_id(id) "nonprofit__CACHE_KEY__ID___#{id}" end - def create_cache_key_for_location(state_code,city, name) + def create_cache_key_for_location(state_code, city, name) "nonprofit__CACHE_KEY__LOCATION___#{state_code}____#{city}___#{name}" end end def clear_cache - Nonprofit::clear_caching(id, state_code_slug, city_slug, slug) + Nonprofit.clear_caching(id, state_code_slug, city_slug, slug) end end concerning :TaxReceipting do - def supporters_who_have_payments_during_year(year, tickets:false) - payments_during_year = self.payments.during_np_year(year) + def supporters_who_have_payments_during_year(year, tickets: false) + payments_during_year = payments.during_np_year(year) unless tickets payments_during_year = payments_during_year.where("kind IS NULL OR kind != ? ", "ticket") end - payments_during_year.group("supporter_id").select('supporter_id, COUNT(id)').each.map(&:supporter) + payments_during_year.group("supporter_id").select("supporter_id, COUNT(id)").each.map(&:supporter) end def supporters_who_have_payments_prior_to_year(year, tickets: false) - payments_during_year = self.payments.during_np_year(year) - payments_during_year.group("supporter_id").select('supporter_id, COUNT(id)').each.map(&:supporter) + payments_during_year = payments.during_np_year(year) + payments_during_year.group("supporter_id").select("supporter_id, COUNT(id)").each.map(&:supporter) end end private def timezone_is_valid - timezone.blank? || ActiveSupport::TimeZone.all.map{ |t| t.tzinfo.name }.include?(timezone) || errors.add(:timezone, 'is not a valid timezone') + timezone.blank? || ActiveSupport::TimeZone.all.map { |t| t.tzinfo.name }.include?(timezone) || errors.add(:timezone, "is not a valid timezone") end end diff --git a/app/models/nonprofit_account.rb b/app/models/nonprofit_account.rb index b5ee62d08..14a3846d5 100644 --- a/app/models/nonprofit_account.rb +++ b/app/models/nonprofit_account.rb @@ -1,13 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class NonprofitAccount < ApplicationRecord + attr_accessible \ + :stripe_account_id, # str + :nonprofit, :nonprofit_id # int - attr_accessible \ - :stripe_account_id, #str - :nonprofit, :nonprofit_id #int - - belongs_to :nonprofit - - validates :nonprofit, presence: true - validates :stripe_account_id, presence: true + belongs_to :nonprofit + validates :nonprofit, presence: true + validates :stripe_account_id, presence: true end diff --git a/app/models/nonprofit_key.rb b/app/models/nonprofit_key.rb index e208b9a71..294810ba1 100644 --- a/app/models/nonprofit_key.rb +++ b/app/models/nonprofit_key.rb @@ -4,9 +4,9 @@ # Actually handled through InsertNonprofitKeys class NonprofitKey < ApplicationRecord - belongs_to :nonprofit, required: true + belongs_to :nonprofit, optional: false - validates_presence_of :mailchimp_token + validates :mailchimp_token, presence: true def mailchimp_token read_attribute(:mailchimp_token).nil? ? nil : Cypher.decrypt(read_attribute(:mailchimp_token)) diff --git a/app/models/nonprofit_s3_key.rb b/app/models/nonprofit_s3_key.rb index 106faf5f9..a27d7f395 100644 --- a/app/models/nonprofit_s3_key.rb +++ b/app/models/nonprofit_s3_key.rb @@ -1,12 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class NonprofitS3Key < ApplicationRecord - belongs_to :nonprofit, required: true + belongs_to :nonprofit, optional: false - validates_presence_of :access_key_id, :secret_access_key, :bucket_name, :region + validates :access_key_id, :secret_access_key, :bucket_name, :region, presence: true def aws_client - ::Aws::S3::Client.new(credentials:credentials, region: region) + ::Aws::S3::Client.new(credentials: credentials, region: region) end def credentials diff --git a/app/models/nonprofit_verification_process_status.rb b/app/models/nonprofit_verification_process_status.rb index a57a45d6e..fc0a91793 100644 --- a/app/models/nonprofit_verification_process_status.rb +++ b/app/models/nonprofit_verification_process_status.rb @@ -1,6 +1,5 @@ class NonprofitVerificationProcessStatus < ApplicationRecord attr_accessible :started_at, :stripe_account_id - belongs_to :stripe_account, foreign_key: :stripe_account_id, primary_key: :stripe_account_id - + belongs_to :stripe_account, primary_key: :stripe_account_id end diff --git a/app/models/object_event.rb b/app/models/object_event.rb index 918f54b1c..e181b7952 100644 --- a/app/models/object_event.rb +++ b/app/models/object_event.rb @@ -1,64 +1,62 @@ # @license License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -=begin -An ObjectEvent represents a change that was made to an Houdini object. For example, when a supporter -is created a "supporter.created" object event is created. Object event names are: - -1. lower case and snake case with no spaces -2. consist of the Houdini object type name (usually, but not always, the class name snake-cased) and -and the event name, both snake_cased, seperated by a period - +# An ObjectEvent represents a change that was made to an Houdini object. For example, when a supporter +# is created a "supporter.created" object event is created. Object event names are: +# +# 1. lower case and snake case with no spaces +# 2. consist of the Houdini object type name (usually, but not always, the class name snake-cased) and +# and the event name, both snake_cased, seperated by a period +# # How to set up object events for a class. - -Setting up object events is pretty straightforward. You have to do the following: - +# +# Setting up object events is pretty straightforward. You have to do the following: +# ## Make sure `#setup_houid` is run on your class. -TIP: have your model inherit from `ApplicationRecord` so `#setup_houid` is available. - -```ruby +# TIP: have your model inherit from `ApplicationRecord` so `#setup_houid` is available. +# +# ```ruby # in app/models/family_object.rb -class FamilyObject < ApplicationRecord - setup_houid :familyobj, :houid -end -``` - +# class FamilyObject < ApplicationRecord +# setup_houid :familyobj, :houid +# end +# ``` +# ## Add a method on your class for the event and which creates a new ObjectEvent - -```ruby +# +# ```ruby # in app/models/family_object.rb -class FamilyObject < ApplicationRecord - setup_houid :familyobj, :houid - - def publish_created # recommended that the method be `publish_` - ObjectEvent.create(event_entity: self, event_type: 'family_object.created') - end -end -``` - +# class FamilyObject < ApplicationRecord +# setup_houid :familyobj, :houid +# +# def publish_created # recommended that the method be `publish_` +# ObjectEvent.create(event_entity: self, event_type: 'family_object.created') +# end +# end +# ``` +# ## Add a jbuilder template for generating the ObjectEvent JSON -Place a jbuilder partial template at `app/views/api_new//object_events/_base.json`, which calls the general Jbuilder partial for the class -and sets what attributes should be expanded. - -```ruby +# Place a jbuilder partial template at `app/views/api_new//object_events/_base.json`, which calls the general Jbuilder partial for the class +# and sets what attributes should be expanded. +# +# ```ruby # in app/views/api_new/class name, snakecased/object_events/_base.json - -json.partial! event_entity, # the object is always passed in as `event_entity` - as: :family_object, # this is the parameter that your class' partial uses - __expand: build_json_expansion_path_tree('parent') # this tells us what parts of the object should be expanded using JSON SPaths - -``` - -@see Controllers::ApiNew::JbuilderExpansions - -@!attribute [r] event_type - @return [String] the type of the ObjectEvent. If a supporter was created, this would be `supporter.created` -@!attribute [r] event_entity_houid - @return [String] the houid of the object that the event occurred on. Automatically set at creation. -@!attribute [r] created - @return [Time] the moment in UTC that the object event was created. Automatically set at creation. -@!attribute [r] object_json - @return [Hash] the json representing the event. Automatically set at creation. -=end +# +# json.partial! event_entity, # the object is always passed in as `event_entity` +# as: :family_object, # this is the parameter that your class' partial uses +# __expand: build_json_expansion_path_tree('parent') # this tells us what parts of the object should be expanded using JSON SPaths +# +# ``` +# +# @see Controllers::ApiNew::JbuilderExpansions +# +# @!attribute [r] event_type +# @return [String] the type of the ObjectEvent. If a supporter was created, this would be `supporter.created` +# @!attribute [r] event_entity_houid +# @return [String] the houid of the object that the event occurred on. Automatically set at creation. +# @!attribute [r] created +# @return [Time] the moment in UTC that the object event was created. Automatically set at creation. +# @!attribute [r] object_json +# @return [Hash] the json representing the event. Automatically set at creation. class ObjectEvent < ApplicationRecord include Model::CreatedTimeable setup_houid :evt, :houid @@ -66,7 +64,7 @@ class ObjectEvent < ApplicationRecord # @option attributes [#to_houid] :event_entity the object that had an event # @option attributes [String] :event_type the name of the event that occurred on an object def initialize(attributes = nil, options = {}) - super(attributes, options) + super end # Event entity is the Houdini object associated with the object event belongs_to :event_entity, polymorphic: true @@ -75,37 +73,37 @@ def initialize(attributes = nil, options = {}) # methods that relate to querying for a nonprofit's (ObjectEvent)s concerning :Query do - class_methods do # Queries the database to find every ObjectEvent associated with a particular object # @param [string] event_entity_houid the Houid of the object whose object events you want to find def event_entity(event_entity_houid) - where(event_entity_houid:event_entity_houid) + where(event_entity_houid: event_entity_houid) end # Queries the database to find every ObjectEvent of a particular type def event_types(types) - where('event_type IN (?)', types) + where("event_type IN (?)", types) end end end before_validation do - write_attribute(:object_json, to_object) if event_entity - write_attribute(:nonprofit_id, event_entity&.nonprofit&.id) if event_entity.respond_to? :nonprofit - write_attribute(:event_entity_houid, event_entity&.houid) + self[:object_json] = to_object if event_entity + self[:nonprofit_id] = event_entity&.nonprofit&.id if event_entity.respond_to? :nonprofit + self[:event_entity_houid] = event_entity&.houid end private + # # Generates the JSON representing the [ObjectEvent] # @return [Object] the JSON representing the ObjectEvent def to_object - JSON.parse((ApiNew::ObjectEventsController.render 'api_new/object_events/generate', + JSON.parse((ApiNew::ObjectEventsController.render "api_new/object_events/generate", assigns: { - object_event:self, + object_event: self, event_entity: event_entity, - partial_path: "api_new/#{event_entity.to_partial_path.split('/').delete_at(0)}/object_events/base" + partial_path: "api_new/#{event_entity.to_partial_path.split("/").delete_at(0)}/object_events/base" })) end end diff --git a/app/models/offline_transaction.rb b/app/models/offline_transaction.rb index 1666dfd3b..bfa55e6a6 100644 --- a/app/models/offline_transaction.rb +++ b/app/models/offline_transaction.rb @@ -4,16 +4,16 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE # rubocop:disable Metrics/BlockLength, Metrics/AbcSize, Metrics/MethodLength class OfflineTransaction < ApplicationRecord - include Model::Subtransactable - delegate :created, to: :subtransaction + include Model::Subtransactable + delegate :created, to: :subtransaction - delegate :net_amount, to: :subtransaction_payments - as_money :amount, :net_amount + delegate :net_amount, to: :subtransaction_payments + as_money :amount, :net_amount - concerning :JBuilder do - included do - setup_houid :offlinetrx, :houid - end - end + concerning :JBuilder do + included do + setup_houid :offlinetrx, :houid + end + end end # rubocop:enable all diff --git a/app/models/offline_transaction_charge.rb b/app/models/offline_transaction_charge.rb index cd95a1605..34f3da2cc 100644 --- a/app/models/offline_transaction_charge.rb +++ b/app/models/offline_transaction_charge.rb @@ -5,35 +5,35 @@ # rubocop:disable Metrics/BlockLength, Metrics/AbcSize class OfflineTransactionCharge < ApplicationRecord - include Model::SubtransactionPaymentable - has_one :legacy_payment, class_name: 'Payment', through: :subtransaction_payment - has_one :offsite_payment, through: :legacy_payment + include Model::SubtransactionPaymentable + has_one :legacy_payment, class_name: "Payment", through: :subtransaction_payment + has_one :offsite_payment, through: :legacy_payment - delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - delegate :currency, to: :nonprofit + delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment + delegate :currency, to: :nonprofit - as_money :gross_amount, :net_amount, :fee_total + as_money :gross_amount, :net_amount, :fee_total - def created - legacy_payment.date - end + def created + legacy_payment.date + end - def publish_created - object_events.create( event_type: 'offline_transaction_charge.created') - end + def publish_created + object_events.create(event_type: "offline_transaction_charge.created") + end - def publish_updated - object_events.create( event_type: 'offline_transaction_charge.updated') - end + def publish_updated + object_events.create(event_type: "offline_transaction_charge.updated") + end - def publish_deleted - object_events.create( event_type: 'offline_transaction_charge.deleted') - end + def publish_deleted + object_events.create(event_type: "offline_transaction_charge.deleted") + end - concerning :JBuilder do - included do - setup_houid :offtrxchrg, :houid - end - end + concerning :JBuilder do + included do + setup_houid :offtrxchrg, :houid + end + end end # rubocop:enable all diff --git a/app/models/offsite_payment.rb b/app/models/offsite_payment.rb index 9a729ed27..3691bea87 100644 --- a/app/models/offsite_payment.rb +++ b/app/models/offsite_payment.rb @@ -1,10 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class OffsitePayment < ApplicationRecord - - attr_accessible :gross_amount, :kind, :date, :check_number - belongs_to :payment, dependent: :destroy - belongs_to :donation - belongs_to :nonprofit - belongs_to :supporter - + attr_accessible :gross_amount, :kind, :date, :check_number + belongs_to :payment, dependent: :destroy + belongs_to :donation + belongs_to :nonprofit + belongs_to :supporter end diff --git a/app/models/payment.rb b/app/models/payment.rb index ecc74d271..d912fef9a 100644 --- a/app/models/payment.rb +++ b/app/models/payment.rb @@ -4,132 +4,128 @@ # If connected to an offsite_payment, this is money the nonprofit is recording for convenience. class Payment < ApplicationRecord - extend ActiveSupport::Concern - + extend ActiveSupport::Concern attr_accessible \ :towards, - :gross_amount, - :refund_total, - :fee_total, - :net_amount, - :kind, - :date, - :nonprofit, - :nonprofit_id, - :supporter_id, - :supporter - - belongs_to :supporter - belongs_to :nonprofit - has_one :charge - has_one :offsite_payment - has_one :refund - has_one :dispute_transaction - has_many :disputes, through: :charge - belongs_to :donation - has_many :tickets - has_one :campaign, through: :donation - has_many :campaign_gifts, through: :donation - has_many :events, through: :tickets - has_many :payment_payouts - has_many :charges - has_one :misc_payment_info - has_one :journal_entries_to_item, as: :item - has_one :payment_dupe_status - has_one :manual_balance_adjustment - - has_one :subtransaction_payment, foreign_key: 'legacy_payment_id', inverse_of: :legacy_payment - - has_one :trx, class_name: 'Transaction', through: :subtransaction_payment - - has_many :activities, :as => :attachment do - def create(attributes=nil, options={}, &block) - attributes = proxy_association.owner.build_activity_attributes.merge(attributes || {}) - proxy_association.create(attributes, options, &block) - end - - def build(attributes=nil, options={}, &block) - attributes = proxy_association.owner.build_activity_attributes.merge(attributes || {}) - proxy_association.build(attributes, options, &block) - end - end - - - def self.find_each_related_to_a_donation - find_each.map(&:from_donation?) - end - - def self.each_related_to_a_donation - each.map(&:from_donation?) - end - - def from_donation? - if kind == 'Refund' - !!refund&.from_donation? - elsif kind == 'Dispute' || kind == 'DisputeReversal' - !!dispute_transaction&.from_donation? - elsif kind == 'OffsitePayment' - !!donation.present? - else - kind == 'Donation' || kind == 'RecurringDonation' - end - end - - - def staff_comment - (manual_balance_adjustment&.staff_comment&.present? && manual_balance_adjustment&.staff_comment) || nil - end - - - scope :anonymous, -> {includes(:donation, :supporter).where('donations.anonymous OR supporters.anonymous').references(:supporters, :donations)} - scope :not_anonymous, -> { includes(:donation, :supporter).where('NOT(donations.anonymous OR supporters.anonymous)').references(:supporters, :donations) } - scope :not_matched, -> { joins('LEFT JOIN payment_dupe_statuses ON payment_dupe_statuses.payment_id = payments.id').where('payment_dupe_statuses.id IS NULL OR NOT payment_dupe_statuses.matched') } - - def consider_anonymous? - !!(supporter&.anonymous || donation&.anonymous) - end - - def build_activity_json - dispute_transaction_payment = self - dispute = dispute_transaction_payment.dispute_transaction.dispute - original_payment = dispute.original_payment - case kind - when 'Dispute', 'DisputeReversed' - return { + :gross_amount, + :refund_total, + :fee_total, + :net_amount, + :kind, + :date, + :nonprofit, + :nonprofit_id, + :supporter_id, + :supporter + + belongs_to :supporter + belongs_to :nonprofit + has_one :charge + has_one :offsite_payment + has_one :refund + has_one :dispute_transaction + has_many :disputes, through: :charge + belongs_to :donation + has_many :tickets + has_one :campaign, through: :donation + has_many :campaign_gifts, through: :donation + has_many :events, through: :tickets + has_many :payment_payouts + has_many :charges + has_one :misc_payment_info + has_one :journal_entries_to_item, as: :item + has_one :payment_dupe_status + has_one :manual_balance_adjustment + + has_one :subtransaction_payment, foreign_key: "legacy_payment_id", inverse_of: :legacy_payment + + has_one :trx, class_name: "Transaction", through: :subtransaction_payment + + has_many :activities, as: :attachment do + def create(attributes = nil, options = {}, &block) + attributes = proxy_association.owner.build_activity_attributes.merge(attributes || {}) + proxy_association.create(attributes, options, &block) + end + + def build(attributes = nil, options = {}, &block) + attributes = proxy_association.owner.build_activity_attributes.merge(attributes || {}) + proxy_association.build(attributes, options, &block) + end + end + + def self.find_each_related_to_a_donation + find_each.map(&:from_donation?) + end + + def self.each_related_to_a_donation + each.map(&:from_donation?) + end + + def from_donation? + if kind == "Refund" + !!refund&.from_donation? + elsif kind == "Dispute" || kind == "DisputeReversal" + !!dispute_transaction&.from_donation? + elsif kind == "OffsitePayment" + !!donation.present? + else + kind == "Donation" || kind == "RecurringDonation" + end + end + + def staff_comment + (manual_balance_adjustment&.staff_comment&.present? && manual_balance_adjustment&.staff_comment) || nil + end + + scope :anonymous, -> { includes(:donation, :supporter).where("donations.anonymous OR supporters.anonymous").references(:supporters, :donations) } + scope :not_anonymous, -> { includes(:donation, :supporter).where("NOT(donations.anonymous OR supporters.anonymous)").references(:supporters, :donations) } + scope :not_matched, -> { joins("LEFT JOIN payment_dupe_statuses ON payment_dupe_statuses.payment_id = payments.id").where("payment_dupe_statuses.id IS NULL OR NOT payment_dupe_statuses.matched") } + + def consider_anonymous? + !!(supporter&.anonymous || donation&.anonymous) + end + + def build_activity_json + dispute_transaction_payment = self + dispute = dispute_transaction_payment.dispute_transaction.dispute + original_payment = dispute.original_payment + case kind + when "Dispute", "DisputeReversed" + { gross_amount: dispute_transaction_payment.gross_amount, fee_total: dispute_transaction_payment.fee_total, - net_amount: dispute_transaction_payment.net_amount, - reason: dispute.reason, - status: dispute.status, - original_id: original_payment.id, - original_kind: original_payment.kind, - original_gross_amount: original_payment.gross_amount, - original_date: original_payment.date, - started_at: dispute.started_at - } - end - end - - def build_activity_attributes - dispute_transaction_payment = self - case kind - when 'Dispute' - return { - kind: 'DisputeFundsWithdrawn', + net_amount: dispute_transaction_payment.net_amount, + reason: dispute.reason, + status: dispute.status, + original_id: original_payment.id, + original_kind: original_payment.kind, + original_gross_amount: original_payment.gross_amount, + original_date: original_payment.date, + started_at: dispute.started_at + } + end + end + + def build_activity_attributes + dispute_transaction_payment = self + case kind + when "Dispute" + { + kind: "DisputeFundsWithdrawn", date: dispute_transaction_payment.date, nonprofit: dispute_transaction_payment.nonprofit, supporter: dispute_transaction_payment.supporter, json_data: build_activity_json } - when 'DisputeReversed' - return { - kind: 'DisputeFundsReinstated', + when "DisputeReversed" + { + kind: "DisputeFundsReinstated", date: dispute_transaction_payment.date, nonprofit: dispute_transaction_payment.nonprofit, supporter: dispute_transaction_payment.supporter, json_data: build_activity_json - } - end - end + } + end + end end diff --git a/app/models/payment_dupe_status.rb b/app/models/payment_dupe_status.rb index 7f21552a4..e3e9abf3e 100644 --- a/app/models/payment_dupe_status.rb +++ b/app/models/payment_dupe_status.rb @@ -1,3 +1,3 @@ class PaymentDupeStatus < ApplicationRecord - belongs_to :payment + belongs_to :payment end diff --git a/app/models/payment_import.rb b/app/models/payment_import.rb index 925e0c38b..8a66c4a4a 100644 --- a/app/models/payment_import.rb +++ b/app/models/payment_import.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class PaymentImport < ApplicationRecord attr_accessible :nonprofit, :user - has_and_belongs_to_many :donations, join_table: 'donations_payment_imports' + has_and_belongs_to_many :donations, join_table: "donations_payment_imports" belongs_to :nonprofit belongs_to :user end diff --git a/app/models/payment_payout.rb b/app/models/payment_payout.rb index 3c686763d..72bbbcb72 100644 --- a/app/models/payment_payout.rb +++ b/app/models/payment_payout.rb @@ -12,18 +12,16 @@ # since our fees will continue to change as our transaction volume increases class PaymentPayout < ApplicationRecord + attr_accessible \ + :payment_id, :payment, + :charge_id, :charge, # deprecated + :payout_id, :payout, + :total_fees # int (cents) - attr_accessible \ - :payment_id, :payment, - :charge_id, :charge, # deprecated - :payout_id, :payout, - :total_fees # int (cents) + belongs_to :charge # deprecated + belongs_to :payment + belongs_to :payout - belongs_to :charge # deprecated - belongs_to :payment - belongs_to :payout - - validates :payment, presence: true - validates :payout, presence: true + validates :payment, presence: true + validates :payout, presence: true end - diff --git a/app/models/payout.rb b/app/models/payout.rb index 0b9cdb11b..3b1abe6f4 100644 --- a/app/models/payout.rb +++ b/app/models/payout.rb @@ -6,70 +6,69 @@ # Unless you're sure, DO NOT CREATE THESE USING STANDARD ACTIVERECORD METHODS. Use `InsertPayout.with_stripe` instead. class Payout < ApplicationRecord + setup_houid :pyout, :houid - setup_houid :pyout, :houid + attr_accessible \ + :scheduled, # bool (whether this was made automatically at the beginning of the month) + :count, # int (number of donations for this payout) + :ach_fee, # int (in cents, the total fee for the payout itself) + :gross_amount, # int (in cents, total amount before fees) + :fee_total, # int (in cents, total amount of fees) + :net_amount, # int (in cents, total amount after fees for this payout) + :email, # str (cache of user email who issued this) + :user_ip, # str (ip address of the user who made this payout) + :status, # str ('pending', 'paid', 'canceled', or 'failed') + :failure_message, # str + :bank_name, # str: cache of the nonprofit's bank name + :stripe_transfer_id, # str + :nonprofit_id, :nonprofit - attr_accessible \ - :scheduled, # bool (whether this was made automatically at the beginning of the month) - :count, # int (number of donations for this payout) - :ach_fee, # int (in cents, the total fee for the payout itself) - :gross_amount, # int (in cents, total amount before fees) - :fee_total, # int (in cents, total amount of fees) - :net_amount, # int (in cents, total amount after fees for this payout) - :email, # str (cache of user email who issued this) - :user_ip, # str (ip address of the user who made this payout) - :status, # str ('pending', 'paid', 'canceled', or 'failed') - :failure_message, # str - :bank_name, # str: cache of the nonprofit's bank name - :stripe_transfer_id, # str - :nonprofit_id, :nonprofit + belongs_to :nonprofit + has_one :bank_account, through: :nonprofit + has_many :payment_payouts + has_many :payments, through: :payment_payouts + has_many :object_events, as: :event_entity - belongs_to :nonprofit - has_one :bank_account, through: :nonprofit - has_many :payment_payouts - has_many :payments, through: :payment_payouts - has_many :object_events, as: :event_entity + validates :stripe_transfer_id, presence: true, uniqueness: true + validates :nonprofit, presence: true + validates :bank_account, presence: true + validates :email, presence: true + validates :net_amount, presence: true, numericality: {greater_than: 0} + validate :nonprofit_must_be_vetted, on: :create + validate :nonprofit_must_have_identity_verified, on: :create + validate :bank_account_must_be_confirmed, on: :create - validates :stripe_transfer_id, presence: true, uniqueness: true - validates :nonprofit, presence: true - validates :bank_account, presence: true - validates :email, presence: true - validates :net_amount, presence: true, numericality: {greater_than: 0} - validate :nonprofit_must_be_vetted, on: :create - validate :nonprofit_must_have_identity_verified, on: :create - validate :bank_account_must_be_confirmed, on: :create + delegate :currency, to: :nonprofit - delegate :currency, to: :nonprofit + as_money :net_amount - as_money :net_amount + scope :pending, -> { where(status: "pending") } + scope :paid, -> { where(status: ["paid", "succeeded"]) } - scope :pending, -> {where(status: 'pending')} - scope :paid, -> {where(status: ['paid', 'succeeded'])} + # Older transfers use the Stripe::Transfer object, newer use Stripe::Payout object + def transfer_type + if stripe_transfer_id.start_with?("tr_", "test_tr_") + :transfer + elsif stripe_transfer_id.start_with?("po_", "test_po_") + :payout + end + end - # Older transfers use the Stripe::Transfer object, newer use Stripe::Payout object - def transfer_type - if (stripe_transfer_id.start_with?('tr_') || stripe_transfer_id.start_with?('test_tr_')) - return :transfer - elsif (stripe_transfer_id.start_with?('po_') || stripe_transfer_id.start_with?('test_po_')) - return :payout - end - end + def bank_account_must_be_confirmed + if bank_account && bank_account.pending_verification + errors.add(:bank_account, "must be confirmed via email") + end + end - def bank_account_must_be_confirmed - if self.bank_account && self.bank_account.pending_verification - self.errors.add(:bank_account, 'must be confirmed via email') - end - end + def nonprofit_must_have_identity_verified + errors.add(:nonprofit, "must be verified") unless nonprofit && nonprofit&.stripe_account&.payouts_enabled + end - def nonprofit_must_have_identity_verified - self.errors.add(:nonprofit, "must be verified") unless self.nonprofit && self.nonprofit&.stripe_account&.payouts_enabled - end + def nonprofit_must_be_vetted + errors.add(:nonprofit, "must be vetted") unless nonprofit && nonprofit.vetted + end - def nonprofit_must_be_vetted - self.errors.add(:nonprofit, "must be vetted") unless self.nonprofit && self.nonprofit.vetted - end - - def publish_created - object_events.create(event_type: 'payout.created') - end + def publish_created + object_events.create(event_type: "payout.created") + end end diff --git a/app/models/periodic_report.rb b/app/models/periodic_report.rb index 2a440d4a2..28ffe9964 100644 --- a/app/models/periodic_report.rb +++ b/app/models/periodic_report.rb @@ -1,13 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class PeriodicReport < ApplicationRecord - # active # boolean, # report_type # string, # period # string, # users, # nonprofit_id - belongs_to :nonprofit, required: true + belongs_to :nonprofit, optional: false has_and_belongs_to_many :users belongs_to :nonprofit_s3_key @@ -30,31 +29,31 @@ class PeriodicReport < ApplicationRecord private_constant :AVAILABLE_PERIODS def valid_report_type? - errors.add(:report_type, 'must be a supported report type') unless AVAILABLE_REPORT_TYPES.include? report_type&.to_sym + errors.add(:report_type, "must be a supported report type") unless AVAILABLE_REPORT_TYPES.include? report_type&.to_sym end def valid_period? - errors.add(:period, 'must be a supported period') unless AVAILABLE_PERIODS.include? period&.to_sym + errors.add(:period, "must be a supported period") unless AVAILABLE_PERIODS.include? period&.to_sym end def valid_nonprofit_s3_key? - errors.add(:nonprofit_s3_key, 'must belong to the nonprofit set via :nonprofit') if nonprofit_s3_key.present? && nonprofit_s3_key.nonprofit != nonprofit + errors.add(:nonprofit_s3_key, "must belong to the nonprofit set via :nonprofit") if nonprofit_s3_key.present? && nonprofit_s3_key.nonprofit != nonprofit end def valid_users? - errors.add(:users, 'must be a list of users') if self.users.none? + errors.add(:users, "must be a list of users") if users.none? users_authorized_to_have_report? end def users_authorized_to_have_report? - self.users.each do |user| - unless nonprofit.users.include?(user) || user.roles&.pluck(:name)&.include?('super_admin') - errors.add(:users, 'must be a user of the nonprofit or a super admin') + users.each do |user| + unless nonprofit.users.include?(user) || user.roles&.pluck(:name)&.include?("super_admin") + errors.add(:users, "must be a user of the nonprofit or a super admin") end end end def adapter - PeriodicReportAdapter.build({ report_type: report_type, nonprofit_id: nonprofit_id, period: period, users: users, nonprofit_s3_key: nonprofit_s3_key, filename:filename }) + PeriodicReportAdapter.build({report_type: report_type, nonprofit_id: nonprofit_id, period: period, users: users, nonprofit_s3_key: nonprofit_s3_key, filename: filename}) end end diff --git a/app/models/profile.rb b/app/models/profile.rb index 0dc5e4939..d5168d048 100755 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -1,113 +1,111 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Profile < ApplicationRecord - - attr_accessible \ - :registered, # bool - :mini_bio, - :first_name, # str - :last_name, # str - :name, - :phone, # str - :address, # str - :email, # str - :city, # str - :state_code, # str (eg. CA) - :zip_code, # str - :picture, # str: either their social network pic or a stored pic on S3 - :anonymous, # bool: negates all privacy_settings - :city_state, - :user_id - - validates :email, format: {with: Email::Regex}, allow_blank: true - - attr_accessor :email, :city_state - - mount_uploader :picture, ProfileUploader - - belongs_to :user - has_many :activities # Activities this profile has created - has_many :supporters - has_many :donations - has_many :campaigns - has_many :events - has_many :recurring_donations - has_many :nonprofits, through: :supporters - has_many :activities, dependent: :destroy -# has_one :card, as: :holder - - #accepts_nested_attributes_for :card - - scope :non_anon, -> {where(anonymous: [nil, false])} - - before_validation(on: :create) do - self.set_defaults - self - end - - def set_defaults - self.name ||= self.user.name if self.user - self.email ||= self.user.email if self.user - self.picture ||= self.user.picture if self.user - if self.name.blank? && self.first_name.present? && self.last_name.present? - self.name ||= self.first_name + ' ' + self.last_name - end - end - - # Queries - - def recent_donations(npo_id) - self.donations.valid.order("created_at").where(nonprofit_id: npo_id).take(10) - end - - # Attrs - - def total_given_to(nonprofit) - self.donations.valid.where(nonprofit_id: nonprofit.id).pluck(:amount).sum - end - - def monthly_giving(nonprofit_id) - self.donations.where(nonprofit_id: nonprofit_id).map(&:amount).sum - end - - def monthly_total_giving - self.donations.map(&:amount).sum - end - - def full_name - "#{self.first_name} #{self.last_name}" - end - - def supporter_name - self.name.blank? ? "A Supporter" : self.name - end - - def get_profile_picture(size=:normal) - # Can be, in order of precedence: your uploaded photo or - # default image - if self.picture? - return self.picture_url(size) - end - # Either does not want photo shown or has none uploaded. - return Image::DefaultProfileUrl - end - - def url - Rails.application.routes.url_helpers.profile_path(self) - end - - def as_json(options = {}) - h = super(options) - h[:pic_tiny] = self.get_profile_picture :tiny - h[:url] = self.url - h - end - - # Cache setters - - def set_caches! - self.total_raised = self.donations.pluck(:amount).sum - self.total_recurring = self.recurring_donations.active.pluck(:amount).sum - self.save! - end - + attr_accessible \ + :registered, # bool + :mini_bio, + :first_name, # str + :last_name, # str + :name, + :phone, # str + :address, # str + :email, # str + :city, # str + :state_code, # str (eg. CA) + :zip_code, # str + :picture, # str: either their social network pic or a stored pic on S3 + :anonymous, # bool: negates all privacy_settings + :city_state, + :user_id + + validates :email, format: {with: Email::Regex}, allow_blank: true + + attr_accessor :email, :city_state + + mount_uploader :picture, ProfileUploader + + belongs_to :user + has_many :activities # Activities this profile has created + has_many :supporters + has_many :donations + has_many :campaigns + has_many :events + has_many :recurring_donations + has_many :nonprofits, through: :supporters + has_many :activities, dependent: :destroy + # has_one :card, as: :holder + + # accepts_nested_attributes_for :card + + scope :non_anon, -> { where(anonymous: [nil, false]) } + + before_validation(on: :create) do + set_defaults + self + end + + def set_defaults + self.name ||= user.name if user + self.email ||= user.email if user + self.picture ||= user.picture if user + if self.name.blank? && first_name.present? && last_name.present? + self.name ||= first_name + " " + last_name + end + end + + # Queries + + def recent_donations(npo_id) + donations.valid.order("created_at").where(nonprofit_id: npo_id).take(10) + end + + # Attrs + + def total_given_to(nonprofit) + donations.valid.where(nonprofit_id: nonprofit.id).pluck(:amount).sum + end + + def monthly_giving(nonprofit_id) + donations.where(nonprofit_id: nonprofit_id).map(&:amount).sum + end + + def monthly_total_giving + donations.map(&:amount).sum + end + + def full_name + "#{first_name} #{last_name}" + end + + def supporter_name + self.name.presence || "A Supporter" + end + + def get_profile_picture(size = :normal) + # Can be, in order of precedence: your uploaded photo or + # default image + if picture? + return picture_url(size) + end + # Either does not want photo shown or has none uploaded. + Image::DefaultProfileUrl + end + + def url + Rails.application.routes.url_helpers.profile_path(self) + end + + def as_json(options = {}) + h = super + h[:pic_tiny] = get_profile_picture :tiny + h[:url] = url + h + end + + # Cache setters + + def set_caches! + self.total_raised = donations.pluck(:amount).sum + self.total_recurring = recurring_donations.active.pluck(:amount).sum + save! + end end diff --git a/app/models/reassignment.rb b/app/models/reassignment.rb index d980d58f8..02d38fa16 100644 --- a/app/models/reassignment.rb +++ b/app/models/reassignment.rb @@ -1,6 +1,6 @@ class Reassignment < ApplicationRecord - belongs_to :item, polymorphic: true - belongs_to :e_tap_import - belongs_to :source_supporter, class_name: 'Supporter', foreign_key: 'source_supporter_id' - belongs_to :target_supporter, class_name: 'Supporter', foreign_key: 'target_supporter_id' + belongs_to :item, polymorphic: true + belongs_to :e_tap_import + belongs_to :source_supporter, class_name: "Supporter" + belongs_to :target_supporter, class_name: "Supporter" end diff --git a/app/models/recurring_donation.rb b/app/models/recurring_donation.rb index ac283e5e2..5955176c1 100644 --- a/app/models/recurring_donation.rb +++ b/app/models/recurring_donation.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class RecurringDonation < ApplicationRecord - # The status is confusing here. # A recurring donation can be in one of four status' # * active @@ -14,10 +13,8 @@ class RecurringDonation < ApplicationRecord # else if the end_date is set and in the past, "fulfilled" # else "active" - # The query that displays in nonprofits/:id/recurring_donations is rds that are active OR failed - define_model_callbacks :cancel before_save :set_anonymous @@ -40,20 +37,20 @@ class RecurringDonation < ApplicationRecord :cancelled_at, # datetime of user/supporter who made the cancellation :donation_id, :donation, :nonprofit_id, :nonprofit, - :supporter_id, #used because things are messed up in the datamodel + :supporter_id, # used because things are messed up in the datamodel :anonymous - scope :active, -> {where(active: true)} - scope :inactive, -> {where(active: [false,nil])} - scope :cancelled, -> {where(active: [false, nil])} - scope :monthly, -> {where(time_unit: 'month', interval: 1)} - scope :annual, -> {where(time_unit: 'year', interval: 1)} - scope :failed, -> {where('n_failures >= 3')} - scope :unfailed, -> {where('n_failures < 3')} - scope :fulfilled, -> {where('recurring_donations.end_date < ?', Time.current.to_date)} - scope :unfulfilled, -> {where('recurring_donations.end_date IS NULL OR recurring_donations.end_date IS >= ?', Time.current.to_date)} + scope :active, -> { where(active: true) } + scope :inactive, -> { where(active: [false, nil]) } + scope :cancelled, -> { where(active: [false, nil]) } + scope :monthly, -> { where(time_unit: "month", interval: 1) } + scope :annual, -> { where(time_unit: "year", interval: 1) } + scope :failed, -> { where("n_failures >= 3") } + scope :unfailed, -> { where("n_failures < 3") } + scope :fulfilled, -> { where("recurring_donations.end_date < ?", Time.current.to_date) } + scope :unfulfilled, -> { where("recurring_donations.end_date IS NULL OR recurring_donations.end_date IS >= ?", Time.current.to_date) } - scope :may_attempt_again, -> {where('recurring_donations.active AND (recurring_donations.end_date IS NULL OR recurring_donations.end_date > ?) AND recurring_donations.n_failures < 3', Time.current)} + scope :may_attempt_again, -> { where("recurring_donations.active AND (recurring_donations.end_date IS NULL OR recurring_donations.end_date > ?) AND recurring_donations.n_failures < 3", Time.current) } belongs_to :donation belongs_to :nonprofit @@ -62,7 +59,7 @@ class RecurringDonation < ApplicationRecord has_one :supporter, through: :donation has_one :misc_recurring_donation_info has_one :recurring_donation_hold - has_many :activities, :as => :attachment + has_many :activities, as: :attachment validates :paydate, numericality: {less_than: 29}, allow_blank: true validates :donation_id, presence: true @@ -73,22 +70,21 @@ class RecurringDonation < ApplicationRecord validates_associated :donation def most_recent_charge - if (self.charges) - return self.charges.sort_by { |c| c.created_at }.last() + if charges + charges.sort_by { |c| c.created_at }.last end end def most_recent_paid_charge - if (self.charges) - return self.charges.find_all {|c| c.paid?}.sort_by { |c| c.created_at }.last() + if charges + charges.find_all { |c| c.paid? }.sort_by { |c| c.created_at }.last end end def total_given - if (self.charges) - return self.charges.find_all(&:paid?).sum(&:amount) + if charges + charges.find_all(&:paid?).sum(&:amount) end - end def failed? @@ -101,31 +97,33 @@ def cancelled? # will this recurring donation be attempted again the next time it should be run? def will_attempt_again? - !failed? && !cancelled? && (end_date.nil? || end_date > Time.current); + !failed? && !cancelled? && (end_date.nil? || end_date > Time.current) end def cancel!(email) - run_callbacks(:cancel) do - self.active = false - self.cancelled_by = email - self.cancelled_at = Time.current - save! - end unless cancelled? + unless cancelled? + run_callbacks(:cancel) do + self.active = false + self.cancelled_by = email + self.cancelled_at = Time.current + save! + end + end end # XXX let's make these monthly_totals a query # Or just push it into the front-end def self.monthly_total - self.all.map(&:monthly_total).sum + all.map(&:monthly_total).sum end def monthly_total multiple = { - 'week' => 4, - 'day' => 30, - 'year' => 0.0833 - }[self.interval] || 1 - return self.donation.amount * multiple + "week" => 4, + "day" => 30, + "year" => 0.0833 + }[interval] || 1 + donation.amount * multiple end private diff --git a/app/models/refund.rb b/app/models/refund.rb index 017667508..b6bd67336 100644 --- a/app/models/refund.rb +++ b/app/models/refund.rb @@ -1,41 +1,37 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Refund < ApplicationRecord - - Reasons = [:duplicate, :fraudulent, :requested_by_customer] - - attr_accessible \ - :amount, # int - :comment, # text - :reason, # str ('duplicate', 'fraudulent', or 'requested_by_customer') - :stripe_refund_id, - :disbursed, # boolean (whether this refund has been counted in a payout) - :failure_message, # str (accessor for storing the Stripe error message) - :user_id, :user, # user who made this refund - :payment_id, :payment, # negative payment that records this refund - :charge_id, :charge - - attr_accessor :failure_message - - belongs_to :charge - belongs_to :payment - has_one :subtransaction_payment, through: :payment - has_one :misc_refund_info - has_one :nonprofit, through: :charge - has_one :supporter, through: :charge - - scope :not_disbursed, ->{where(disbursed: [nil, false])} - scope :disbursed, ->{where(disbursed: [true])} - - has_many :manual_balance_adjustments, as: :entity - - - def original_payment - charge&.payment - end - - def from_donation? - !!original_payment&.donation - end - + Reasons = [:duplicate, :fraudulent, :requested_by_customer] + + attr_accessible \ + :amount, # int + :comment, # text + :reason, # str ('duplicate', 'fraudulent', or 'requested_by_customer') + :stripe_refund_id, + :disbursed, # boolean (whether this refund has been counted in a payout) + :failure_message, # str (accessor for storing the Stripe error message) + :user_id, :user, # user who made this refund + :payment_id, :payment, # negative payment that records this refund + :charge_id, :charge + + attr_accessor :failure_message + + belongs_to :charge + belongs_to :payment + has_one :subtransaction_payment, through: :payment + has_one :misc_refund_info + has_one :nonprofit, through: :charge + has_one :supporter, through: :charge + + scope :not_disbursed, -> { where(disbursed: [nil, false]) } + scope :disbursed, -> { where(disbursed: [true]) } + + has_many :manual_balance_adjustments, as: :entity + + def original_payment + charge&.payment + end + + def from_donation? + !!original_payment&.donation + end end - diff --git a/app/models/role.rb b/app/models/role.rb index b4b73afa9..8803fb9ba 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,52 +1,57 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Role < ApplicationRecord - - Names = [ - :super_admin, # global access - :super_associate, # global access to everything except bank acct info - :nonprofit_admin, # npo scoped access to everything - :nonprofit_associate, # npo scoped access to everything except bank acct info - :campaign_editor, # fundraising tools, without dashboard access - :event_editor # // - ] - - attr_accessible \ - :name, - :user_id, :user, - :host, :host_id, :host_type # nil, "Nonprofit", "Campaign", "Event" - - belongs_to :user - belongs_to :host, polymorphic: true - - scope :super_admins, -> {where(name: :super_admin)} - scope :super_associate, -> {where(name: :super_associate)} - scope :nonprofit_admins, -> {where(name: :nonprofit_admin)} - scope :nonprofit_personnel, -> {where(name: [:nonprofit_associate, :nonprofit_admin])} - scope :campaign_editors, -> {where(name: :campaign_editor)} - scope :event_editors, -> {where(name: :event_editor)} - - validates :user, presence: true - validates :name, inclusion: {in: Names} - validates :host, presence: true, unless: [:super_admin?, :super_associate?] - - def name; super.to_sym; end - def super_admin?; name == :super_admin; end - def super_associate?; name == :super_associate; end - - def self.create_for_nonprofit(role_name, email, nonprofit) - user = User.find_or_create_with_email(email) - role = Role.create(user: user, name: role_name, host: nonprofit) - return role unless role.valid? - - MailchimpNonprofitUserAddJob.perform_later(user, nonprofit) - - if user.confirmed? - NonprofitAdminMailer.delay.existing_invite(role) - else - NonprofitAdminMailer.delay.new_invite(role, user.make_confirmation_token!) - end - return role - end - + Names = [ + :super_admin, # global access + :super_associate, # global access to everything except bank acct info + :nonprofit_admin, # npo scoped access to everything + :nonprofit_associate, # npo scoped access to everything except bank acct info + :campaign_editor, # fundraising tools, without dashboard access + :event_editor # // + ] + + attr_accessible \ + :name, + :user_id, :user, + :host, :host_id, :host_type # nil, "Nonprofit", "Campaign", "Event" + + belongs_to :user + belongs_to :host, polymorphic: true + + scope :super_admins, -> { where(name: :super_admin) } + scope :super_associate, -> { where(name: :super_associate) } + scope :nonprofit_admins, -> { where(name: :nonprofit_admin) } + scope :nonprofit_personnel, -> { where(name: [:nonprofit_associate, :nonprofit_admin]) } + scope :campaign_editors, -> { where(name: :campaign_editor) } + scope :event_editors, -> { where(name: :event_editor) } + + validates :user, presence: true + validates :name, inclusion: {in: Names} + validates :host, presence: true, unless: [:super_admin?, :super_associate?] + + def name + super.to_sym + end + + def super_admin? + name == :super_admin + end + + def super_associate? + name == :super_associate + end + + def self.create_for_nonprofit(role_name, email, nonprofit) + user = User.find_or_create_with_email(email) + role = Role.create(user: user, name: role_name, host: nonprofit) + return role unless role.valid? + + MailchimpNonprofitUserAddJob.perform_later(user, nonprofit) + + if user.confirmed? + NonprofitAdminMailer.delay.existing_invite(role) + else + NonprofitAdminMailer.delay.new_invite(role, user.make_confirmation_token!) + end + role + end end - diff --git a/app/models/simple_object.rb b/app/models/simple_object.rb index e8b57e82b..f7f03b24a 100644 --- a/app/models/simple_object.rb +++ b/app/models/simple_object.rb @@ -9,13 +9,13 @@ class SimpleObject < ApplicationRecord belongs_to :parent, class_name: "SimpleObject" belongs_to :nonprofit - has_many :friends, class_name: "SimpleObject", foreign_key: 'friend_id' + has_many :friends, class_name: "SimpleObject", foreign_key: "friend_id" def publish_created - ObjectEvent.create(event_entity:self, event_type: 'simple_object.created') + ObjectEvent.create(event_entity: self, event_type: "simple_object.created") end def publish_updated - ObjectEvent.create(event_entity:self, event_type: 'simple_object.updated') + ObjectEvent.create(event_entity: self, event_type: "simple_object.updated") end end diff --git a/app/models/source_token.rb b/app/models/source_token.rb index 8fd9a3264..b95b24909 100644 --- a/app/models/source_token.rb +++ b/app/models/source_token.rb @@ -3,13 +3,13 @@ class SourceToken < ApplicationRecord self.primary_key = :token attr_accessible :expiration, :token, :max_uses, :total_uses - belongs_to :tokenizable, :polymorphic => true + belongs_to :tokenizable, polymorphic: true belongs_to :event - scope :expired, -> { where('max_uses <= total_uses OR expiration < ?', Time.now)} - scope :unexpired, -> { where(' NOT (max_uses <= total_uses OR expiration < ?)', Time.now) } + scope :expired, -> { where("max_uses <= total_uses OR expiration < ?", Time.now) } + scope :unexpired, -> { where(" NOT (max_uses <= total_uses OR expiration < ?)", Time.now) } - scope :last_used_more_than_a_month_ago, -> {where('source_tokens.updated_at < ? ', 1.month.ago)} + scope :last_used_more_than_a_month_ago, -> { where("source_tokens.updated_at < ? ", 1.month.ago) } def expired? max_uses <= total_uses || source_token.expiration < Time.now diff --git a/app/models/stripe_account.rb b/app/models/stripe_account.rb index a15143d28..a57007f57 100644 --- a/app/models/stripe_account.rb +++ b/app/models/stripe_account.rb @@ -1,12 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class StripeAccount < ApplicationRecord - attr_accessible :object, :stripe_account_id + attr_accessible :object, :stripe_account_id has_one :nonprofit, primary_key: :stripe_account_id has_one :nonprofit_verification_process_status, primary_key: :stripe_account_id ## this scopes let you find accounts that do or do not have a future_requirements attribute - scope :with_future_requirements, -> {where("object->'future_requirements' IS NOT NULL") } - scope :without_future_requirements, -> {where("object->'future_requirements' IS NULL") } + scope :with_future_requirements, -> { where("object->'future_requirements' IS NOT NULL") } + scope :without_future_requirements, -> { where("object->'future_requirements' IS NULL") } def object=(input) serialize_on_update(input) @@ -14,37 +14,35 @@ def object=(input) def verification_status if pending_verification.any? - result = :pending + :pending elsif needs_immediate_validation_info - result = :unverified + :unverified elsif needs_more_validation_info - result = :temporarily_verified + :temporarily_verified else - result = :verified + :verified end - result end def requirements - Requirements.new(object['requirements']) + Requirements.new(object["requirements"]) end def future_requirements - Requirements.new(object['future_requirements'] || {}) + Requirements.new(object["future_requirements"] || {}) end # the distinct union of the current pending_verification and the future pending_verification values - def pending_verification + def pending_verification (requirements.pending_verification + future_requirements.pending_verification).uniq end - # describes a deadline where additional requirements are needed to be completed # future_requirements can have a current_deadline and not have any additional requirements so # we don't consider that a deadline here. def deadline deadlines = [] - if requirements.current_deadline + if requirements.current_deadline deadlines.push(requirements.current_deadline) end if future_requirements.current_deadline && future_requirements.any_requirements_other_than_external_account?( @@ -67,79 +65,75 @@ def needs_immediate_validation_info end def retrieve_from_stripe - Stripe::Account.retrieve(stripe_account_id, {stripe_version: '2020-08-27'}) + Stripe::Account.retrieve(stripe_account_id, {stripe_version: "2020-08-27"}) end def update_from_stripe update(object: retrieve_from_stripe) end - private - def serialize_on_update(input) + private + def serialize_on_update(input) object_json = nil - + case input when Stripe::Account - write_attribute(:object, input.to_hash) - object_json = self.object - puts self.object + self[:object] = input.to_hash + object_json = object + puts object when String - write_attribute(:object, input) - object_json = self.object + self[:object] = input + object_json = object end - self.charges_enabled = !!object_json['charges_enabled'] - self.payouts_enabled = !!object_json['payouts_enabled'] - requirements = Requirements.new( object_json['requirements']) - self.disabled_reason = requirements.disabled_reason + self.charges_enabled = !!object_json["charges_enabled"] + self.payouts_enabled = !!object_json["payouts_enabled"] + requirements = Requirements.new(object_json["requirements"]) + self.disabled_reason = requirements.disabled_reason self.currently_due = requirements.currently_due - self.past_due = requirements.past_due - self.eventually_due = requirements.eventually_due + self.past_due = requirements.past_due + self.eventually_due = requirements.eventually_due self.pending_verification = requirements.pending_verification - unless self.stripe_account_id - self.stripe_account_id = object_json['id'] + unless stripe_account_id + self.stripe_account_id = object_json["id"] end - self.object + object end - # describes the Stripe Account Requirements in a more pleasant way class Requirements def initialize(requirements) @requirements = requirements || {} end - + def current_deadline - if @requirements['current_deadline'] && @requirements['current_deadline'].to_i != 0 - Time.at(@requirements['current_deadline'].to_i) - else - nil + if @requirements["current_deadline"] && @requirements["current_deadline"].to_i != 0 + Time.at(@requirements["current_deadline"].to_i) end end - + def disabled_reason - @requirements['disabled_reason'] + @requirements["disabled_reason"] end - + def currently_due - @requirements['currently_due'] || [] + @requirements["currently_due"] || [] end - + def past_due - @requirements['past_due'] || [] + @requirements["past_due"] || [] end - + def eventually_due - @requirements['eventually_due'] || [] + @requirements["eventually_due"] || [] end - def any_requirements_other_than_external_account?(opts={}) - + def any_requirements_other_than_external_account?(opts = {}) defaults = { include_eventually_due: false, - include_pending_verification: false, + include_pending_verification: false } opts = defaults.merge(opts) @@ -153,14 +147,14 @@ def any_requirements_other_than_external_account?(opts={}) end requirement_arrays.any? do |i| - !i.none? && !i.all? do |j| - j.starts_with?('external_account') - end + !i.none? && !i.all? do |j| + j.starts_with?("external_account") end + end end - + def pending_verification - @requirements['pending_verification'] || [] + @requirements["pending_verification"] || [] end end end diff --git a/app/models/stripe_charge.rb b/app/models/stripe_charge.rb index fb9f04f3b..7a4053391 100644 --- a/app/models/stripe_charge.rb +++ b/app/models/stripe_charge.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class StripeCharge < ApplicationRecord - attr_accessible :object, :stripe_charge_id - has_one :charge, primary_key: :stripe_charge_id, foreign_key: :stripe_charge_id + attr_accessible :object, :stripe_charge_id + has_one :charge, primary_key: :stripe_charge_id def object=(input) serialize_on_update(input) @@ -10,24 +10,23 @@ def object=(input) def stripe_object Stripe::Util.convert_to_stripe_object(object) end - + private - def serialize_on_update(input) + def serialize_on_update(input) object_json = nil - + case input when Stripe::Charge - write_attribute(:object, input.to_hash) - object_json = self.object + self[:object] = input.to_hash + object_json = object when String - write_attribute(:object, input) - object_json = self.object + self[:object] = input + object_json = object end - - self.stripe_charge_id = object_json['id'] + self.stripe_charge_id = object_json["id"] - self.object + object end end diff --git a/app/models/stripe_dispute.rb b/app/models/stripe_dispute.rb index 03cfeab22..cb3ffbf9e 100644 --- a/app/models/stripe_dispute.rb +++ b/app/models/stripe_dispute.rb @@ -1,10 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class StripeDispute < ApplicationRecord + TERMINAL_DISPUTE_STATUSES = ["won", "lost"] - TERMINAL_DISPUTE_STATUSES = ['won', 'lost'] - - attr_accessible :object, :stripe_dispute_id - has_one :dispute, primary_key: :stripe_dispute_id, foreign_key: :stripe_dispute_id + attr_accessible :object, :stripe_dispute_id + has_one :dispute, primary_key: :stripe_dispute_id has_one :charge, primary_key: :stripe_charge_id, foreign_key: :stripe_charge_id after_save :fire_change_events @@ -17,43 +16,43 @@ def balance_transactions_state end def funds_withdrawn_balance_transaction - balance_transactions.any? ? balance_transactions.sort_by{|i| i['created']}[0] : nil + balance_transactions.any? ? balance_transactions.sort_by { |i| i["created"] }[0] : nil end def funds_reinstated_balance_transaction - balance_transactions.count == 2 ? balance_transactions.sort_by{|i| i['created']}[1] : nil + (balance_transactions.count == 2) ? balance_transactions.sort_by { |i| i["created"] }[1] : nil end - + private - def serialize_on_update(input) + def serialize_on_update(input) object_json = nil - + case input when Stripe::Dispute - write_attribute(:object, input.to_hash) - object_json = self.object + self[:object] = input.to_hash + object_json = object when String - write_attribute(:object, input) - object_json = self.object + self[:object] = input + object_json = object end - self.balance_transactions = object_json['balance_transactions'] - - self.reason = object_json['reason'] - self.status = object_json['status'] - self.net_change = object_json['balance_transactions'].map{|i| i['net']}.sum - self.amount = object_json['amount'] - self.stripe_dispute_id = object_json['id'] - self.stripe_charge_id = object_json['charge'] - self.evidence_due_date = (object_json['evidence_details'] && object_json['evidence_details']['due_by']) ? - Time.at(object_json['evidence_details']['due_by']) : + self.balance_transactions = object_json["balance_transactions"] + + self.reason = object_json["reason"] + self.status = object_json["status"] + self.net_change = object_json["balance_transactions"].map { |i| i["net"] }.sum + self.amount = object_json["amount"] + self.stripe_dispute_id = object_json["id"] + self.stripe_charge_id = object_json["charge"] + self.evidence_due_date = (object_json["evidence_details"] && object_json["evidence_details"]["due_by"]) ? + Time.at(object_json["evidence_details"]["due_by"]) : nil - self.started_at = Time.at(object_json['created']) + self.started_at = Time.at(object_json["created"]) - self.object + object end - + def fire_change_events if saved_changes? && !dispute&.is_legacy if after_save_changed_attributes["object"].nil? @@ -66,21 +65,21 @@ def fire_change_events old_state = StripeDispute.calc_balance_transaction_state(old_bt) if old_state != balance_transactions_state - if (old_state == :none) - if( balance_transactions_state == :funds_withdrawn) + if old_state == :none + if balance_transactions_state == :funds_withdrawn dispute_funds_withdrawn_event else dispute_funds_withdrawn_event dispute_funds_reinstated_event end - elsif (old_state == :funds_withdrawn) - if (balance_transactions_state == :funds_reinstated) + elsif old_state == :funds_withdrawn + if balance_transactions_state == :funds_reinstated dispute_funds_reinstated_event else raise RuntimeError("Dispute #{dispute.id} previously had a balance_transaction_state of #{old_state} but is now #{balance_transactions_state}. " + "This shouldn't be possible.") end - elsif (balance_transactions_state != :funds_reinstated) + elsif balance_transactions_state != :funds_reinstated raise RuntimeError("Dispute #{dispute.id} previously had a balance_transaction_state of #{old_state} but is now #{balance_transactions_state}. " + "This shouldn't be possible.") end @@ -88,48 +87,44 @@ def fire_change_events end if saved_change_to_attribute?(:status) - if TERMINAL_DISPUTE_STATUSES.include?(after_save_changed_attributes['status']) && !TERMINAL_DISPUTE_STATUSES.include?(status) + if TERMINAL_DISPUTE_STATUSES.include?(after_save_changed_attributes["status"]) && !TERMINAL_DISPUTE_STATUSES.include?(status) # if previous status was won or lost and the new one isn't - raise RuntimeError("Dispute #{dispute.id} was previously #{after_save_changed_attributes['status']} but is now #{status}. " + + raise RuntimeError("Dispute #{dispute.id} was previously #{after_save_changed_attributes["status"]} but is now #{status}. " + "This shouldn't be possible") - elsif (!TERMINAL_DISPUTE_STATUSES.include?(after_save_changed_attributes['status']) && TERMINAL_DISPUTE_STATUSES.include?(status)) + elsif !TERMINAL_DISPUTE_STATUSES.include?(after_save_changed_attributes["status"]) && TERMINAL_DISPUTE_STATUSES.include?(status) # previous status was not won or lost but the new one is dispute_closed_event - else - if (after_save_changed_attributes["status"] != nil) - # previous status was not won or lost but the new one still isn't but there were changes! - dispute_updated_event - end + elsif !after_save_changed_attributes["status"].nil? + # previous status was not won or lost but the new one still isn't but there were changes! + dispute_updated_event end - elsif (!saved_change_to_attribute?(:balance_transactions) && after_save_changed_attributes["object"].nil?) + elsif !saved_change_to_attribute?(:balance_transactions) && after_save_changed_attributes["object"].nil? dispute_updated_event end end end def dispute_created_event - create_dispute!(charge:charge, status:status, reason: reason, gross_amount:amount, started_at: started_at) - + create_dispute!(charge: charge, status: status, reason: reason, gross_amount: amount, started_at: started_at) + # notify folks of the event being opened - dispute.activities.create('DisputeCreated', started_at) + dispute.activities.create("DisputeCreated", started_at) JobQueue.queue(JobTypes::DisputeCreatedJob, dispute) end def dispute_funds_withdrawn_event gross_amount = funds_withdrawn_balance_transaction["amount"] - fee_total = -1 * funds_withdrawn_balance_transaction['fee'] - transaction = dispute.dispute_transactions.create(gross_amount:gross_amount, fee_total: fee_total , - payment: dispute.supporter.payments.create(nonprofit: dispute.nonprofit, - gross_amount:gross_amount, + fee_total = -1 * funds_withdrawn_balance_transaction["fee"] + transaction = dispute.dispute_transactions.create(gross_amount: gross_amount, fee_total: fee_total, + payment: dispute.supporter.payments.create(nonprofit: dispute.nonprofit, + gross_amount: gross_amount, fee_total: fee_total, net_amount: gross_amount + fee_total, - kind: 'Dispute', - date: Time.at(funds_withdrawn_balance_transaction["created"]) - ), - stripe_transaction_id: funds_withdrawn_balance_transaction['id'], - date: Time.at(funds_withdrawn_balance_transaction["created"]) - ) + kind: "Dispute", + date: Time.at(funds_withdrawn_balance_transaction["created"])), + stripe_transaction_id: funds_withdrawn_balance_transaction["id"], + date: Time.at(funds_withdrawn_balance_transaction["created"])) # add dispute payment activity transaction.payment.activities.create @@ -142,18 +137,16 @@ def dispute_funds_withdrawn_event def dispute_funds_reinstated_event gross_amount = funds_reinstated_balance_transaction["amount"] - fee_total = -1 * funds_reinstated_balance_transaction['fee'] - transaction = dispute.dispute_transactions.create(gross_amount:gross_amount, fee_total: fee_total, - payment: dispute.supporter.payments.create(nonprofit: dispute.nonprofit, - gross_amount:gross_amount, + fee_total = -1 * funds_reinstated_balance_transaction["fee"] + transaction = dispute.dispute_transactions.create(gross_amount: gross_amount, fee_total: fee_total, + payment: dispute.supporter.payments.create(nonprofit: dispute.nonprofit, + gross_amount: gross_amount, fee_total: fee_total, net_amount: gross_amount + fee_total, - kind: 'DisputeReversed', - date: Time.at(funds_reinstated_balance_transaction["created"]) - ), - stripe_transaction_id: funds_reinstated_balance_transaction['id'], - date: Time.at(funds_reinstated_balance_transaction["created"]) - ) + kind: "DisputeReversed", + date: Time.at(funds_reinstated_balance_transaction["created"])), + stripe_transaction_id: funds_reinstated_balance_transaction["id"], + date: Time.at(funds_reinstated_balance_transaction["created"])) transaction.dispute.original_payment.refund_total += gross_amount * -1 transaction.dispute.original_payment.save! @@ -165,11 +158,11 @@ def dispute_funds_reinstated_event def dispute_closed_event dispute.status = status dispute.save! - if (dispute.status == 'won') - dispute.activities.create('DisputeWon', Time.now) + if dispute.status == "won" + dispute.activities.create("DisputeWon", Time.now) JobQueue.queue(JobTypes::DisputeWonJob, dispute) - elsif dispute.status == 'lost' - dispute.activities.create('DisputeLost', Time.now) + elsif dispute.status == "lost" + dispute.activities.create("DisputeLost", Time.now) JobQueue.queue(JobTypes::DisputeLostJob, dispute) else raise RuntimeError("Dispute #{dispute.id} was closed " + @@ -178,20 +171,22 @@ def dispute_closed_event end def dispute_updated_event - dispute.activities.create('DisputeUpdated', Time.now) + dispute.activities.create("DisputeUpdated", Time.now) JobQueue.queue(JobTypes::DisputeUpdatedJob, dispute) end def self.calc_balance_transaction_state(balance_transactions) - !balance_transactions || balance_transactions.count == 0 ? - :none : - balance_transactions.count == 1 ? - :funds_withdrawn : - :funds_reinstated + if !balance_transactions || balance_transactions.count == 0 + :none + else + (balance_transactions.count == 1) ? + :funds_withdrawn : + :funds_reinstated + end end private - + def after_save_changed_attributes saved_changes.transform_values(&:first) end diff --git a/app/models/stripe_event.rb b/app/models/stripe_event.rb index 0915a1050..0e26dd65a 100644 --- a/app/models/stripe_event.rb +++ b/app/models/stripe_event.rb @@ -5,9 +5,9 @@ class StripeEvent < ApplicationRecord def self.process_dispute(event) StripeEvent.transaction do object = event.data.object - events_for_object_id = StripeEvent.where('object_id = ?', object.id).lock(true) + events_for_object_id = StripeEvent.where("object_id = ?", object.id).lock(true) - event_record = events_for_object_id.where('event_id = ?', event.id).first + event_record = events_for_object_id.where("event_id = ?", event.id).first # if event_record found, we've recorded this event so no processing necessary unless event_record @@ -15,18 +15,16 @@ def self.process_dispute(event) stripe_event = StripeEvent.new(event_id: event.id, event_time: Time.at(event.created).to_datetime, object_id: event.data.object.id) stripe_event.save! - later_event = events_for_object_id.where('event_time > ?', Time.at(event.created).to_datetime).first + later_event = events_for_object_id.where("event_time > ?", Time.at(event.created).to_datetime).first # we have a later event so we don't need to process this anymore unless later_event LockManager.with_transaction_lock(object.id) do - object = Stripe::Dispute.retrieve(object.id) - dispute = StripeDispute.where("stripe_dispute_id = ?", object.id).first - unless dispute - dispute = StripeDispute.new(stripe_dispute_id: object.id) - end - dispute.object = object - dispute.save! + object = Stripe::Dispute.retrieve(object.id) + dispute = StripeDispute.where("stripe_dispute_id = ?", object.id).first + dispute ||= StripeDispute.new(stripe_dispute_id: object.id) + dispute.object = object + dispute.save! end end end @@ -36,9 +34,9 @@ def self.process_dispute(event) def self.process_charge(event) StripeEvent.transaction do object = event.data.object - events_for_object_id = StripeEvent.where('object_id = ?', object.id).lock(true) + events_for_object_id = StripeEvent.where("object_id = ?", object.id).lock(true) - event_record = events_for_object_id.where('event_id = ?', event.id).first + event_record = events_for_object_id.where("event_id = ?", event.id).first # if event_record found, we've recorded this event so no processing necessary unless event_record @@ -46,18 +44,16 @@ def self.process_charge(event) stripe_event = StripeEvent.new(event_id: event.id, event_time: Time.at(event.created).to_datetime, object_id: event.data.object.id) stripe_event.save! - later_event = events_for_object_id.where('event_time > ?', Time.at(event.created).to_datetime).first + later_event = events_for_object_id.where("event_time > ?", Time.at(event.created).to_datetime).first # we have a later event so we don't need to process this anymore unless later_event LockManager.with_transaction_lock(object.id) do - object = Stripe::Charge.retrieve(object.id) - charge = StripeCharge.where("stripe_charge_id = ?", object.id).first - unless charge - charge = StripeCharge.new(stripe_charge_id: object.id) - end - charge.object = object - charge.save! + object = Stripe::Charge.retrieve(object.id) + charge = StripeCharge.where("stripe_charge_id = ?", object.id).first + charge ||= StripeCharge.new(stripe_charge_id: object.id) + charge.object = object + charge.save! end end end @@ -66,12 +62,12 @@ def self.process_charge(event) def self.handle(event) case event.type - when 'account.updated' + when "account.updated" StripeEvent.transaction do object = event.data.object - events_for_object_id = StripeEvent.where('object_id = ?', object.id).lock(true) + events_for_object_id = StripeEvent.where("object_id = ?", object.id).lock(true) - event_record = events_for_object_id.where('event_id = ?', event.id).first + event_record = events_for_object_id.where("event_id = ?", event.id).first # if event_record found, we've recorded this event so no processing necessary unless event_record @@ -79,68 +75,65 @@ def self.handle(event) stripe_event = StripeEvent.new(event_id: event.id, event_time: Time.at(event.created).to_datetime, object_id: event.data.object.id) stripe_event.save! - later_event = events_for_object_id.where('event_time > ?', Time.at(event.created).to_datetime).first + later_event = events_for_object_id.where("event_time > ?", Time.at(event.created).to_datetime).first # we have a later event so we don't need to process this anymore unless later_event previous_verification_status = nil account = StripeAccount.where("stripe_account_id = ?", object.id).first - if account - account.lock!('FOR UPDATE') + if account + account.lock!("FOR UPDATE") previous_verification_status = account.verification_status - else + else account = StripeAccount.new(stripe_account_id: object.id) - end - - status = NonprofitVerificationProcessStatus.where(stripe_account_id: object.id).first - - account.object = object - account.save! - - - unless status.nil? - if [:verified, :temporarily_verified].include?(account.verification_status) - status.destroy if status.persisted? - #send validation email - StripeAccountMailer.delay.conditionally_send_verified(account) - else - status.email_to_send_guid = SecureRandom.uuid - - if previous_verification_status == :pending - StripeAccountMailer.delay(run_at: DateTime.now + NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY).conditionally_send_more_info_needed(account, status.email_to_send_guid) - else - StripeAccountMailer.delay(run_at: DateTime.now + NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY).conditionally_send_not_completed(account, status.email_to_send_guid) - end - - status.save! - end + end + + status = NonprofitVerificationProcessStatus.where(stripe_account_id: object.id).first + + account.object = object + account.save! + + if status.nil? + if previous_verification_status == :verified && account.verification_status == :unverified + StripeAccountMailer.delay.conditionally_send_no_longer_verified(account) + end + elsif [:verified, :temporarily_verified].include?(account.verification_status) + status.destroy if status.persisted? + # send validation email + StripeAccountMailer.delay.conditionally_send_verified(account) + else + status.email_to_send_guid = SecureRandom.uuid + + if previous_verification_status == :pending + StripeAccountMailer.delay(run_at: DateTime.now + NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY).conditionally_send_more_info_needed(account, status.email_to_send_guid) else - if previous_verification_status == :verified && account.verification_status == :unverified - StripeAccountMailer.delay.conditionally_send_no_longer_verified(account) - end + StripeAccountMailer.delay(run_at: DateTime.now + NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY).conditionally_send_not_completed(account, status.email_to_send_guid) end + + status.save! end + end end end - when 'charge.dispute.created' + when "charge.dispute.created" process_dispute(event) - when 'charge.dispute.funds_withdrawn' + when "charge.dispute.funds_withdrawn" process_dispute(event) - when 'charge.dispute.funds_reinstated' + when "charge.dispute.funds_reinstated" process_dispute(event) - when 'charge.dispute.closed' + when "charge.dispute.closed" process_dispute(event) - when 'charge.captured' + when "charge.captured" process_charge(event) - when 'charge.expired' + when "charge.expired" process_charge(event) - when 'charge.failed' + when "charge.failed" process_charge(event) - when 'charge.pending' + when "charge.pending" process_charge(event) - when 'charge.succeeded' + when "charge.succeeded" process_charge(event) - when 'charge.updated' + when "charge.updated" process_charge(event) end end diff --git a/app/models/stripe_transaction.rb b/app/models/stripe_transaction.rb index a4a24c573..00b6b935f 100644 --- a/app/models/stripe_transaction.rb +++ b/app/models/stripe_transaction.rb @@ -3,29 +3,29 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class StripeTransaction < ApplicationRecord - include Model::Subtransactable - setup_houid :stripetrx, :houid - delegate :created, to: :subtransaction - delegate :net_amount, to: :subtransaction_payments + include Model::Subtransactable + setup_houid :stripetrx, :houid + delegate :created, to: :subtransaction + delegate :net_amount, to: :subtransaction_payments - as_money :amount, :net_amount + as_money :amount, :net_amount - # Handle a completed refund from a legacy Refund object - def process_refund(refund) - refund = self.subtransaction.subtransaction_payments.create!(paymentable:StripeTransactionRefund.new, subtransaction: subtransaction, legacy_payment: refund.payment) - update!(amount: subtransaction_payments.gross_amount) - refund - end + # Handle a completed refund from a legacy Refund object + def process_refund(refund) + refund = subtransaction.subtransaction_payments.create!(paymentable: StripeTransactionRefund.new, subtransaction: subtransaction, legacy_payment: refund.payment) + update!(amount: subtransaction_payments.gross_amount) + refund + end - def publish_created - #object_events.create( event_type: 'stripe_transaction.created') - end + def publish_created + # object_events.create( event_type: 'stripe_transaction.created') + end - def publish_updated - #object_events.create( event_type: 'stripe_transaction.updated') - end + def publish_updated + # object_events.create( event_type: 'stripe_transaction.updated') + end - def publish_deleted - #object_events.create( event_type: 'stripe_transaction.deleted') - end + def publish_deleted + # object_events.create( event_type: 'stripe_transaction.deleted') + end end diff --git a/app/models/stripe_transaction_charge.rb b/app/models/stripe_transaction_charge.rb index 9cbc4d354..2e7bca6b9 100644 --- a/app/models/stripe_transaction_charge.rb +++ b/app/models/stripe_transaction_charge.rb @@ -4,31 +4,31 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class StripeTransactionCharge < ApplicationRecord include Model::SubtransactionPaymentable - setup_houid :stripechrg, :houid - - has_one :legacy_payment, class_name: 'Payment', through: :subtransaction_payment - - delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - - as_money :gross_amount, :net_amount, :fee_total - - def created - legacy_payment.date - end + setup_houid :stripechrg, :houid + + has_one :legacy_payment, class_name: "Payment", through: :subtransaction_payment + + delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment + + as_money :gross_amount, :net_amount, :fee_total + + def created + legacy_payment.date + end def stripe_id - legacy_payment.charge.stripe_charge_id - end + legacy_payment.charge.stripe_charge_id + end - def publish_created - object_events.create( event_type: 'stripe_transaction_charge.created') - end + def publish_created + object_events.create(event_type: "stripe_transaction_charge.created") + end - def publish_updated - object_events.create( event_type: 'stripe_transaction_charge.updated') - end + def publish_updated + object_events.create(event_type: "stripe_transaction_charge.updated") + end - def publish_deleted - object_events.create( event_type: 'stripe_transaction_charge.deleted') - end + def publish_deleted + object_events.create(event_type: "stripe_transaction_charge.deleted") + end end diff --git a/app/models/stripe_transaction_dispute.rb b/app/models/stripe_transaction_dispute.rb index 1270a1f20..0d81ddde9 100644 --- a/app/models/stripe_transaction_dispute.rb +++ b/app/models/stripe_transaction_dispute.rb @@ -3,31 +3,31 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class StripeTransactionDispute < ApplicationRecord - include Model::SubtransactionPaymentable - setup_houid :stripedisp, :houid - has_one :legacy_payment, class_name: 'Payment', through: :subtransaction_payment + include Model::SubtransactionPaymentable + setup_houid :stripedisp, :houid + has_one :legacy_payment, class_name: "Payment", through: :subtransaction_payment - delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - - as_money :gross_amount, :net_amount, :fee_total + delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - def created - legacy_payment.date - end + as_money :gross_amount, :net_amount, :fee_total - # def stripe_id - # legacy_payment.dispute.stripe_dispute_id - # end + def created + legacy_payment.date + end - def publish_created - object_events.create( event_type: 'stripe_transaction_dispute.created') - end + # def stripe_id + # legacy_payment.dispute.stripe_dispute_id + # end - def publish_updated - object_events.create( event_type: 'stripe_transaction_dispute.updated') - end + def publish_created + object_events.create(event_type: "stripe_transaction_dispute.created") + end - def publish_deleted - object_events.create( event_type: 'stripe_transaction_dispute.deleted') - end + def publish_updated + object_events.create(event_type: "stripe_transaction_dispute.updated") + end + + def publish_deleted + object_events.create(event_type: "stripe_transaction_dispute.deleted") + end end diff --git a/app/models/stripe_transaction_dispute_reversal.rb b/app/models/stripe_transaction_dispute_reversal.rb index 3e47f5780..319cd7457 100644 --- a/app/models/stripe_transaction_dispute_reversal.rb +++ b/app/models/stripe_transaction_dispute_reversal.rb @@ -3,31 +3,30 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class StripeTransactionDisputeReversal < ApplicationRecord - include Model::SubtransactionPaymentable + include Model::SubtransactionPaymentable setup_houid :stripedisprvrs, :houid - has_one :legacy_payment, class_name: 'Payment', through: :subtransaction_payment + has_one :legacy_payment, class_name: "Payment", through: :subtransaction_payment - delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment + delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - delegate :currency, to: :nonprofit - - as_money :gross_amount, :net_amount, :fee_total + delegate :currency, to: :nonprofit - def created - legacy_payment.date - end + as_money :gross_amount, :net_amount, :fee_total + def created + legacy_payment.date + end - def publish_created - object_events.create( event_type: 'stripe_transaction_dispute_reversal.created') - end + def publish_created + object_events.create(event_type: "stripe_transaction_dispute_reversal.created") + end - def publish_updated - object_events.create( event_type: 'stripe_transaction_dispute_reversal.updated') - end + def publish_updated + object_events.create(event_type: "stripe_transaction_dispute_reversal.updated") + end - def publish_deleted - object_events.create( event_type: 'stripe_transaction_dispute_reversal.deleted') - end -end \ No newline at end of file + def publish_deleted + object_events.create(event_type: "stripe_transaction_dispute_reversal.deleted") + end +end diff --git a/app/models/stripe_transaction_refund.rb b/app/models/stripe_transaction_refund.rb index e17d6622f..8451f455b 100644 --- a/app/models/stripe_transaction_refund.rb +++ b/app/models/stripe_transaction_refund.rb @@ -3,34 +3,32 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class StripeTransactionRefund < ApplicationRecord - include Model::SubtransactionPaymentable + include Model::SubtransactionPaymentable setup_houid :striperef, :houid - has_one :legacy_payment, class_name: 'Payment', through: :subtransaction_payment + has_one :legacy_payment, class_name: "Payment", through: :subtransaction_payment - delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - - as_money :gross_amount, :net_amount, :fee_total + delegate :gross_amount, :net_amount, :fee_total, to: :legacy_payment - def created - legacy_payment.date - end + as_money :gross_amount, :net_amount, :fee_total + def created + legacy_payment.date + end - def stripe_id - legacy_payment.refund.stripe_refund_id - end + def stripe_id + legacy_payment.refund.stripe_refund_id + end - def publish_created - object_events.create( event_type: 'stripe_transaction_refund.created') - end + def publish_created + object_events.create(event_type: "stripe_transaction_refund.created") + end - def publish_updated - object_events.create( event_type: 'stripe_transaction_refund.updated') - end + def publish_updated + object_events.create(event_type: "stripe_transaction_refund.updated") + end - def publish_deleted - object_events.create( event_type: 'stripe_transaction_refund.deleted') - end - -end \ No newline at end of file + def publish_deleted + object_events.create(event_type: "stripe_transaction_refund.deleted") + end +end diff --git a/app/models/subtransaction.rb b/app/models/subtransaction.rb index ba10a378d..785fc01b3 100644 --- a/app/models/subtransaction.rb +++ b/app/models/subtransaction.rb @@ -3,27 +3,27 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class Subtransaction < ApplicationRecord - include Model::CreatedTimeable + include Model::CreatedTimeable - belongs_to :trx, class_name: 'Transaction', foreign_key: 'transaction_id', inverse_of: :subtransaction - has_one :supporter, through: :trx - has_one :nonprofit, through: :trx - delegate :currency, to: :nonprofit + belongs_to :trx, class_name: "Transaction", foreign_key: "transaction_id", inverse_of: :subtransaction + has_one :supporter, through: :trx + has_one :nonprofit, through: :trx + delegate :currency, to: :nonprofit - belongs_to :subtransactable, polymorphic: true + belongs_to :subtransactable, polymorphic: true - has_many :subtransaction_payments, -> { extending ModelExtensions::PaymentsExtension } # rubocop:disable Rails/HasManyOrHasOneDependent + has_many :subtransaction_payments, -> { extending ModelExtensions::PaymentsExtension } # rubocop:disable Rails/HasManyOrHasOneDependent - # get payments in reverse chronological order - def ordered_payments - subtransaction_payments.ordered - end + # get payments in reverse chronological order + def ordered_payments + subtransaction_payments.ordered + end - delegated_type :subtransactable, types: %w[OfflineTransaction, StripeTransaction] + delegated_type :subtransactable, types: %w[OfflineTransaction, StripeTransaction] - delegate :to_houid, :process_refund, :publish_updated, to: :subtransactable + delegate :to_houid, :process_refund, :publish_updated, to: :subtransactable - as_money :amount + as_money :amount - validates_presence_of :subtransactable + validates :subtransactable, presence: true end diff --git a/app/models/subtransaction_payment.rb b/app/models/subtransaction_payment.rb index 2fab99937..56dd655ed 100644 --- a/app/models/subtransaction_payment.rb +++ b/app/models/subtransaction_payment.rb @@ -3,31 +3,30 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class SubtransactionPayment < ApplicationRecord - include Model::CreatedTimeable + include Model::CreatedTimeable + # get payments in reverse chronological order using SQL + scope :ordered_query, -> { + includes(:legacy_payment).references(:legacy_payments).order("payments.date DESC").order("subtransaction_payments.updated_at DESC") + } - # get payments in reverse chronological order using SQL - scope :ordered_query, -> { - includes(:legacy_payment).references(:legacy_payments).order("payments.date DESC").order("subtransaction_payments.updated_at DESC") - } + belongs_to :subtransaction, inverse_of: :subtransaction_payments + has_one :trx, class_name: "Transaction", foreign_key: "transaction_id", through: :subtransaction + has_one :supporter, through: :subtransaction + has_one :nonprofit, through: :subtransaction + belongs_to :legacy_payment, class_name: "Payment", optional: false - belongs_to :subtransaction, inverse_of: :subtransaction_payments - has_one :trx, class_name: 'Transaction', foreign_key: 'transaction_id', through: :subtransaction - has_one :supporter, through: :subtransaction - has_one :nonprofit, through: :subtransaction - belongs_to :legacy_payment, class_name: 'Payment', required: true + delegated_type :paymentable, types: %w[ + OfflineTransactionCharge + OfflineTransactionDispute + OfflineTransactionRefund + StripeTransactionCharge + StripeTransactionRefund + StripeTransactionDispute + StripeTransactionDisputeReversal + ] - delegated_type :paymentable, types: %w[ - OfflineTransactionCharge - OfflineTransactionDispute - OfflineTransactionRefund - StripeTransactionCharge - StripeTransactionRefund - StripeTransactionDispute - StripeTransactionDisputeReversal - ] + delegate :gross_amount, :fee_total, :net_amount, :publish_created, :publish_updated, :publish_deleted, :to_houid, to: :paymentable - delegate :gross_amount, :fee_total, :net_amount, :publish_created, :publish_updated, :publish_deleted, :to_houid, to: :paymentable - - validates_presence_of :paymentable + validates :paymentable, presence: true end diff --git a/app/models/supporter.rb b/app/models/supporter.rb index 4d856653e..9ff373045 100644 --- a/app/models/supporter.rb +++ b/app/models/supporter.rb @@ -4,7 +4,7 @@ class Supporter < ApplicationRecord include Model::CalculatedNames setup_houid :supp, :houid - ADDRESS_FIELDS = ['address', 'city', 'state_code', 'country', 'zip_code'] + ADDRESS_FIELDS = ["address", "city", "state_code", "country", "zip_code"] before_validation :cleanup_address before_validation :cleanup_name @@ -12,7 +12,7 @@ class Supporter < ApplicationRecord before_save :update_primary_address attr_accessor :address_line2 - + attr_accessible \ :profile_id, :profile, :nonprofit_id, :nonprofit, @@ -37,15 +37,15 @@ class Supporter < ApplicationRecord :fields, :anonymous, :deleted, # bool (flag for soft delete) - :email_unsubscribe_uuid, #string - :is_unsubscribed_from_emails, #bool + :email_unsubscribe_uuid, # string + :is_unsubscribed_from_emails, # bool :id, :created_at, :address_line2, :primary_address # fts is generated via a trigger - attr_readonly :fts + attr_readonly :fts belongs_to :profile belongs_to :nonprofit @@ -54,24 +54,24 @@ class Supporter < ApplicationRecord has_many :payments do def during_np_year(year) proxy_association.owner.nonprofit.use_zone do - where('payments.date >= ? and payments.date < ?', Time.zone.local(year), Time.zone.local(year + 1)) + where("payments.date >= ? and payments.date < ?", Time.zone.local(year), Time.zone.local(year + 1)) end end def donation_payments - where('kind IN (?)', ['Donation', 'RecurringDonation']) + where("kind IN (?)", ["Donation", "RecurringDonation"]) end def refund_payments - where('kind IN (?)', ['Refund']) + where("kind IN (?)", ["Refund"]) end def dispute_payments - where('kind IN (?)', ['Dispute']) + where("kind IN (?)", ["Dispute"]) end def dispute_reversal_payments - where('kind IN (?)', ['DisputeReversed']) + where("kind IN (?)", ["DisputeReversed"]) end end has_many :offsite_payments @@ -95,7 +95,7 @@ def dispute_reversal_payments included do has_many :tag_joins, dependent: :destroy has_many :tag_masters, through: :tag_joins - has_many :undeleted_tag_masters, -> { not_deleted }, through: :tag_joins, source: 'tag_master' + has_many :undeleted_tag_masters, -> { not_deleted }, through: :tag_joins, source: "tag_master" end end @@ -106,7 +106,7 @@ def dispute_reversal_payments has_many :active_email_lists, through: :undeleted_tag_masters, source: :email_list do def update_member_on_all_lists proxy_association.reload.target.each do |list| # We're reloading the association and running .each on target - #to make sure we get any newly saved email lists. I think this should be simpler but I'm not sure how to do it. + # to make sure we get any newly saved email lists. I think this should be simpler but I'm not sure how to do it. MailchimpSignupJob.perform_later(proxy_association.owner, list) end end @@ -120,34 +120,33 @@ def must_update_email_lists? end def publish_created - object_events.create(event_type: 'supporter.created') + object_events.create(event_type: "supporter.created") end private - + def try_update_member_on_all_lists update_member_on_all_lists if must_update_email_lists? - end + end def update_member_on_all_lists active_email_lists.update_member_on_all_lists end - end - + has_many :custom_field_joins, dependent: :destroy has_many :custom_field_masters, through: :custom_field_joins - belongs_to :merged_into, class_name: 'Supporter', :foreign_key => 'merged_into' - has_many :merged_from, class_name: 'Supporter', :foreign_key => "merged_into" + belongs_to :merged_into, class_name: "Supporter", foreign_key: "merged_into" + has_many :merged_from, class_name: "Supporter", foreign_key: "merged_into" has_many :addresses, class_name: "SupporterAddress", after_add: :set_address_to_primary_if_needed belongs_to :primary_address, class_name: "SupporterAddress" - validates :nonprofit, :presence => true - scope :not_deleted, -> {where(deleted: false)} - scope :deleted, -> {where(deleted: true)} - scope :merged, -> {where('merged_at IS NOT NULL')} - scope :not_merged, -> {where('merged_at IS NULL')} + validates :nonprofit, presence: true + scope :not_deleted, -> { where(deleted: false) } + scope :deleted, -> { where(deleted: true) } + scope :merged, -> { where.not(merged_at: nil) } + scope :not_merged, -> { where("merged_at IS NULL") } geocoded_by :full_address reverse_geocoded_by :latitude, :longitude do |obj, results| @@ -161,9 +160,9 @@ def update_member_on_all_lists end end - def profile_picture size=:normal - return unless self.profile - self.profile.get_profile_picture(size) + def profile_picture size = :normal + return unless profile + profile.get_profile_picture(size) end concerning :Path do @@ -173,7 +172,7 @@ def profile_picture size=:normal included do # When you use a routing helper like `api_new_nonprofit_supporter``, you need to provide objects which have a `#to_param` # method. By default that's set to the value of `#id`. In our case, for the api objects, we want the id to instead be - # the value of `#houid`. We can't override `to_param` though because we may use route helpers which expect `#to_param` to + # the value of `#houid`. We can't override `to_param` though because we may use route helpers which expect `#to_param` to # return the value of `#id`. This is the hacky workaround. def to_modern_param ModernParams.new(houid) @@ -181,44 +180,42 @@ def to_modern_param end end - - # Supporters can be merged many times. This finds the last # supporter after following merged_into until it gets a nil def end_of_merge_chain if merged_into.nil? - return self + self else merged_into.end_of_merge_chain end end - def as_json(options = {}) - h = super(options) - h[:pic_tiny] = self.profile_picture(:tiny) - h[:pic_normal] = self.profile_picture(:normal) - h[:url] = self.profile && Rails.application.routes.url_helpers.profile_path(self.profile) - return h + h = super + h[:pic_tiny] = profile_picture(:tiny) + h[:pic_normal] = profile_picture(:normal) + h[:url] = profile && Rails.application.routes.url_helpers.profile_path(profile) + h end def full_address - Format::Address.full_address(self.address, self.city, self.state_code) + Format::Address.full_address(address, city, state_code) end private + def cleanup_address if address.present? && address_line2.present? - assign_attributes(address_line2: nil, address: self.address + " " + self.address_line2) + assign_attributes(address_line2: nil, address: address + " " + address_line2) end address_field_attributes.each do |addr_attribute, addr_value| self[addr_attribute] = nil if addr_value.blank? end end - def cleanup_name + def cleanup_name if first_name.present? || last_name.present? - assign_attributes(name: [first_name&.strip, last_name&.strip].select{|i| i.present?}.join(" ")) + assign_attributes(name: [first_name&.strip, last_name&.strip].select { |i| i.present? }.join(" ")) assign_attributes(first_name: nil, last_name: nil) end end @@ -232,17 +229,17 @@ def filled_address_fields? end def update_primary_address - if self.changes.slice(*ADDRESS_FIELDS).any? #changed an address field + if changes.slice(*ADDRESS_FIELDS).any? # changed an address field if filled_address_fields? if primary_address.nil? - self.addresses.build(address_field_attributes) + addresses.build(address_field_attributes) else primary_address.update(address_field_attributes) end elsif primary_address.present? prim_addr = primary_address - self.update(primary_address: nil) - self.addresses.delete(prim_addr) + update(primary_address: nil) + addresses.delete(prim_addr) prim_addr.destroy end end diff --git a/app/models/supporter_address.rb b/app/models/supporter_address.rb index 6bfa715b1..1b35af304 100644 --- a/app/models/supporter_address.rb +++ b/app/models/supporter_address.rb @@ -1,6 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SupporterAddress < ApplicationRecord - belongs_to :supporter, required:true, inverse_of: :addresses + belongs_to :supporter, optional: false, inverse_of: :addresses def primary? supporter&.primary_address == self diff --git a/app/models/supporter_email.rb b/app/models/supporter_email.rb index 0e9b2e530..e90d4c97c 100644 --- a/app/models/supporter_email.rb +++ b/app/models/supporter_email.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SupporterEmail < ApplicationRecord - attr_accessible \ - :to, - :from, - :subject, - :body, - :recipient_count, - :supporter_id, :supporter, - :nonprofit_id, - :gmail_thread_id + attr_accessible \ + :to, + :from, + :subject, + :body, + :recipient_count, + :supporter_id, :supporter, + :nonprofit_id, + :gmail_thread_id - belongs_to :supporter - validates_presence_of :nonprofit_id - has_many :activities, as: :attachment, dependent: :destroy + belongs_to :supporter + validates :nonprofit_id, presence: true + has_many :activities, as: :attachment, dependent: :destroy end diff --git a/app/models/supporter_note.rb b/app/models/supporter_note.rb index 7b6da4c4f..4fc96a850 100644 --- a/app/models/supporter_note.rb +++ b/app/models/supporter_note.rb @@ -1,29 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class SupporterNote < ApplicationRecord + attr_accessible \ + :content, + :supporter_id, :supporter, + :user - attr_accessible \ - :content, - :supporter_id, :supporter, - :user + belongs_to :supporter + has_many :activities, as: :attachment, dependent: :destroy + belongs_to :user - belongs_to :supporter - has_many :activities, as: :attachment, dependent: :destroy - belongs_to :user + validates :content, length: {minimum: 1} + validates :supporter, presence: true - validates :content, length: {minimum: 1} - validates :supporter, presence: true + after_create :create_activity - after_create :create_activity + concerning :ETapImport do + included do + has_many :journal_entries_to_items, as: :item + end + end - concerning :ETapImport do - included do - has_many :journal_entries_to_items, as: :item - end - end + private - private - def create_activity - InsertActivities.for_supporter_notes([id]) - end + def create_activity + InsertActivities.for_supporter_notes([id]) + end end - diff --git a/app/models/tag_join.rb b/app/models/tag_join.rb index d531ddb93..2e3bb9c88 100644 --- a/app/models/tag_join.rb +++ b/app/models/tag_join.rb @@ -1,24 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TagJoin < ApplicationRecord + attr_accessible \ + :supporter, :supporter_id, + :tag_master, :tag_master_id - attr_accessible \ - :supporter, :supporter_id, - :tag_master, :tag_master_id + validates :tag_master, presence: true - validates :tag_master, presence: true + belongs_to :tag_master + belongs_to :supporter - belongs_to :tag_master - belongs_to :supporter - - def name; self.tag_master.name; end - - def self.create_with_name(nonprofit, h) - tm = nonprofit.tag_masters.find_by_name(h['name']) - if tm.nil? - tm = nonprofit.tag_masters.create(name: h['name']) - end - self.create tag_master: tm, supporter_id: h['supporter_id'] - end + def name + tag_master.name + end + def self.create_with_name(nonprofit, h) + tm = nonprofit.tag_masters.find_by_name(h["name"]) + if tm.nil? + tm = nonprofit.tag_masters.create(name: h["name"]) + end + create tag_master: tm, supporter_id: h["supporter_id"] + end end - diff --git a/app/models/tag_join/modification.rb b/app/models/tag_join/modification.rb index 727c044c9..98ff4b469 100644 --- a/app/models/tag_join/modification.rb +++ b/app/models/tag_join/modification.rb @@ -7,12 +7,11 @@ class TagJoin::Modification attribute :tag_master_id, :integer attribute :selected, :boolean, default: false - def initialize(opts={}) - super(opts) + def initialize(opts = {}) + super end def tag_master TagMaster.find(tag_master_id) end - end diff --git a/app/models/tag_join/modifications.rb b/app/models/tag_join/modifications.rb index 38846fd7d..22347e014 100644 --- a/app/models/tag_join/modifications.rb +++ b/app/models/tag_join/modifications.rb @@ -1,9 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # Handy class managing a list of requested modifications class TagJoin::Modifications < Array - # accepts an Array containing hashes with the keys `tag_master_id`` and `selected` or `TagJoin::Modification`'s - def initialize(tag_modifications_source=[]) + def initialize(tag_modifications_source = []) super(tag_modifications_source.map do |i| i.is_a?(TagJoin::Modification) ? i : TagJoin::Modification.new(i) end @@ -12,17 +11,17 @@ def initialize(tag_modifications_source=[]) # @return [TagJoin::Modifications] all tags which are selected def selected - TagJoin::Modifications.new(self.select{|i| i.selected}) + TagJoin::Modifications.new(self.select { |i| i.selected }) end # @return [TagJoin::Modifications] all tags which are not selected def unselected - TagJoin::Modifications.new(self.select{|i| !i.selected}) + TagJoin::Modifications.new(self.select { |i| !i.selected }) end # @return [integer] the TagMaster ids of all of the referenced tags def to_tag_master_ids - self.map{|i| i.tag_master_id} + map { |i| i.tag_master_id } end # given a set of ids for TagMaster OR TagMaster objects themeselves, @@ -33,21 +32,20 @@ def to_tag_master_ids # @example passing in a TagMaster # given_tag_master = TagMaster.find(1234) # modifications = TagJoin::Modifications.new([{tag_master_id: 5678, selected: true}, {tag_master_id: 1234, selected: false}]) - # + # # mods_for_tags = modifications.for_given_tags([given_tag_master]) # # => [#] # # - def for_given_tags(tags=[]) + def for_given_tags(tags = []) valid_ids = tags.map do |i| - if (i.is_a? Integer) + if i.is_a? Integer i else i.id end end - TagJoin::Modifications.new(self.select{|i| valid_ids.include? i.tag_master_id}) + TagJoin::Modifications.new(self.select { |i| valid_ids.include? i.tag_master_id }) end - -end \ No newline at end of file +end diff --git a/app/models/tag_master.rb b/app/models/tag_master.rb index 836bdbfb4..0c093b324 100644 --- a/app/models/tag_master.rb +++ b/app/models/tag_master.rb @@ -1,25 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TagMaster < ApplicationRecord + attr_accessible \ + :nonprofit, :nonprofit_id, + :name, + :deleted, + :created_at - attr_accessible \ - :nonprofit, :nonprofit_id, - :name, - :deleted, - :created_at + validates :name, presence: true + validate :no_dupes, on: :create - validates :name, presence: true - validate :no_dupes, on: :create + belongs_to :nonprofit + has_many :tag_joins, dependent: :destroy + has_one :email_list - belongs_to :nonprofit - has_many :tag_joins, dependent: :destroy - has_one :email_list - - scope :not_deleted, ->{where(deleted: [nil,false])} - - def no_dupes - return self if nonprofit.nil? - errors.add(:base, "Duplicate tag") if nonprofit.tag_masters.not_deleted.where(name: name).any? - end + scope :not_deleted, -> { where(deleted: [nil, false]) } + def no_dupes + return self if nonprofit.nil? + errors.add(:base, "Duplicate tag") if nonprofit.tag_masters.not_deleted.where(name: name).any? + end end - diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 28bd0bcee..82de34ef0 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -1,22 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Ticket < ApplicationRecord - attr_accessible :note, :event_discount, :event_discount_id belongs_to :event_discount - belongs_to :supporter - belongs_to :profile - belongs_to :ticket_level - belongs_to :event - belongs_to :charge - belongs_to :card - belongs_to :payment - belongs_to :source_token - belongs_to :ticket_purchase - has_one :nonprofit, through: :event - has_many :activities, as: :attachment, dependent: :destroy + belongs_to :supporter + belongs_to :profile + belongs_to :ticket_level + belongs_to :event + belongs_to :charge + belongs_to :card + belongs_to :payment + belongs_to :source_token + belongs_to :ticket_purchase + has_one :nonprofit, through: :event + has_many :activities, as: :attachment, dependent: :destroy - def related_tickets - payment.tickets.where('id != ?', self.id) - end + def related_tickets + payment.tickets.where.not(id: id) + end end diff --git a/app/models/ticket_level.rb b/app/models/ticket_level.rb index 130157e0a..f598c3eb4 100644 --- a/app/models/ticket_level.rb +++ b/app/models/ticket_level.rb @@ -1,31 +1,29 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TicketLevel < ApplicationRecord - attr_accessible \ - :amount, #integer - :amount_dollars, #accessor, string - :name, #string - :description, #text - :quantity, #integer - :deleted, #bool for soft delete + :amount, # integer + :amount_dollars, # accessor, string + :name, # string + :description, # text + :quantity, # integer + :deleted, # bool for soft delete :event_id, - :admin_only, #bool, only admins can create tickets for this level - :limit, #int: for limiting the number of tickets to be sold - :order #int: order in which to be displayed + :admin_only, # bool, only admins can create tickets for this level + :limit, # int: for limiting the number of tickets to be sold + :order # int: order in which to be displayed attr_accessor :amount_dollars has_many :tickets belongs_to :event - validates :name, :presence => true - validates :event_id, :presence => true + validates :name, presence: true + validates :event_id, presence: true - scope :not_deleted, ->{where(deleted: [false,nil])} + scope :not_deleted, -> { where(deleted: [false, nil]) } before_validation do - self.amount = Format::Currency.dollars_to_cents(self.amount_dollars) if self.amount_dollars.present? - self.amount = 0 if self.amount.nil? + self.amount = Format::Currency.dollars_to_cents(amount_dollars) if amount_dollars.present? + self.amount = 0 if amount.nil? end - end diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index 1c4e7f5a6..14dfbaf0a 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -5,7 +5,7 @@ class TicketPurchase < ApplicationRecord include Model::TrxAssignable - + setup_houid :tktpur, :houid has_many :tickets diff --git a/app/models/transaction.rb b/app/models/transaction.rb index fffc41f4a..43090fa72 100644 --- a/app/models/transaction.rb +++ b/app/models/transaction.rb @@ -3,97 +3,96 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class Transaction < ApplicationRecord - include Model::CreatedTimeable - include Model::Houidable - - setup_houid :trx, :houid - - belongs_to :supporter, required: true - has_one :nonprofit, through: :supporter - - has_many :transaction_assignments, -> { extending ModelExtensions::TransactionAssignment::RefundExtension }, inverse_of: 'trx' - has_many :donations, through: :transaction_assignments, source: :assignable, source_type: 'ModernDonation', inverse_of: 'trx' - has_many :ticket_purchases, through: :transaction_assignments, source: :assignable, source_type: 'TicketPurchase', inverse_of: 'trx' - - has_one :subtransaction, inverse_of: :trx - has_many :payments, -> { extending ModelExtensions::PaymentsExtension }, through: :subtransaction, source: :subtransaction_payments, class_name: 'SubtransactionPayment' - - has_many :object_events, as: :event_entity - - delegate :currency, to: :nonprofit - - as_money :amount - - # get payments in reverse chronological order - def ordered_payments - payments.ordered - end - - # def designation - # donation&.designation - # end - - # def dedication - # donation&.dedication - # end - - concerning :Refunds do - # Handle a completed refund from a legacy Refund object - def process_refund(refund) - new_refund = save_refund(refund) - publish_after_refund(new_refund) - end - - private - - # @param refund Refund a refund object - # @returns StripeTransactionPayment (with a StripeTransactionRefund) represents the new refund - def save_refund(refund) - # add the refund to the subtransaction as a StripeTransactionRefund - new_refund = subtransaction.process_refund(refund) - # update the value of the transaction itself from the subtransaction - self.amount = subtransaction.subtransactable.amount - # refund means we need to adjust the values of the transaction_assignments - transaction_assignments.process_refund(refund) - # save everything - save! - - new_refund - end - - # @param refund StripeTransactionPayment (with a StripeTransactionRefund) represents the new refund - def publish_after_refund(new_refund) - publish_updated - - subtransaction.publish_updated - # we want to publish that every payment has other than the new refund been updated - payments.ordered.select{|i| i != new_refund}.each(&:publish_updated) - # publish that the new_refund has been created - new_refund.publish_created - - # publish that the transaction_assignments have been updated - transaction_assignments.first.publish_updated - end - end - - def publish_created - object_events.create( event_type: 'transaction.created') - end - - def publish_updated - object_events.create( event_type: 'transaction.updated') - end - - def publish_deleted - object_events.create( event_type: 'transaction.deleted') - end - - private - - def to_param - persisted? && houid - end -end + include Model::CreatedTimeable + include Model::Houidable + + setup_houid :trx, :houid + + belongs_to :supporter, optional: false + has_one :nonprofit, through: :supporter + + has_many :transaction_assignments, -> { extending ModelExtensions::TransactionAssignment::RefundExtension }, inverse_of: "trx" + has_many :donations, through: :transaction_assignments, source: :assignable, source_type: "ModernDonation", inverse_of: "trx" + has_many :ticket_purchases, through: :transaction_assignments, source: :assignable, source_type: "TicketPurchase", inverse_of: "trx" + + has_one :subtransaction, inverse_of: :trx + has_many :payments, -> { extending ModelExtensions::PaymentsExtension }, through: :subtransaction, source: :subtransaction_payments, class_name: "SubtransactionPayment" + + has_many :object_events, as: :event_entity + + delegate :currency, to: :nonprofit + + as_money :amount + + # get payments in reverse chronological order + def ordered_payments + payments.ordered + end + + # def designation + # donation&.designation + # end + + # def dedication + # donation&.dedication + # end + + concerning :Refunds do + # Handle a completed refund from a legacy Refund object + def process_refund(refund) + new_refund = save_refund(refund) + publish_after_refund(new_refund) + end + private + + # @param refund Refund a refund object + # @returns StripeTransactionPayment (with a StripeTransactionRefund) represents the new refund + def save_refund(refund) + # add the refund to the subtransaction as a StripeTransactionRefund + new_refund = subtransaction.process_refund(refund) + # update the value of the transaction itself from the subtransaction + self.amount = subtransaction.subtransactable.amount + # refund means we need to adjust the values of the transaction_assignments + transaction_assignments.process_refund(refund) + # save everything + save! + + new_refund + end + + # @param refund StripeTransactionPayment (with a StripeTransactionRefund) represents the new refund + def publish_after_refund(new_refund) + publish_updated + + subtransaction.publish_updated + # we want to publish that every payment has other than the new refund been updated + payments.ordered.select { |i| i != new_refund }.each(&:publish_updated) + # publish that the new_refund has been created + new_refund.publish_created + + # publish that the transaction_assignments have been updated + transaction_assignments.first.publish_updated + end + end + + def publish_created + object_events.create(event_type: "transaction.created") + end + + def publish_updated + object_events.create(event_type: "transaction.updated") + end + + def publish_deleted + object_events.create(event_type: "transaction.deleted") + end + + private + + def to_param + persisted? && houid + end +end ActiveSupport.run_load_hooks(:houdini_transaction, Transaction) diff --git a/app/models/transaction_assignment.rb b/app/models/transaction_assignment.rb index 62ca9af0b..000fd926c 100644 --- a/app/models/transaction_assignment.rb +++ b/app/models/transaction_assignment.rb @@ -3,15 +3,13 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE class TransactionAssignment < ApplicationRecord + delegated_type :assignable, types: ["ModernDonation"] - delegated_type :assignable, types: ['ModernDonation'] - - belongs_to :trx, class_name: 'Transaction', foreign_key: "transaction_id", required:true, inverse_of: :transaction_assignments + belongs_to :trx, class_name: "Transaction", foreign_key: "transaction_id", optional: false, inverse_of: :transaction_assignments has_one :supporter, through: :trx has_one :nonprofit, through: :trx - validates_presence_of :assignable + validates :assignable, presence: true delegate :to_houid, :publish_updated, to: :assignable - end diff --git a/app/models/user.rb b/app/models/user.rb index e61d2afce..b3ae11830 100755 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,140 +1,138 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class User < ApplicationRecord - include Model::CalculatedNames + include Model::CalculatedNames - attr_accessible \ - :email, # str: balidated with Devise - :password, # str: hashed with bcrypt + attr_accessible \ + :email, # str: balidated with Devise + :password, # str: hashed with bcrypt :phone, # str - :location, - :city, - :state_code, - :password_confirmation, # accessor: used on registration - :remember_me, # bool: don't sign user out for a while - :provider, # str: OAuth provider - :uid, # str: OAuth user ID - :pending_password, # bool: User registered with oauth and did not set a password - :name, # str: created with oauth - :auto_generated, # bool: flag whether a password was auto-generated for this account - :referer, # str: ID of the user who referred this account - :latitude, - :longitude, - :reset_password_token, - :reset_password_sent_at, - :picture, # str: url for fb or twitter pic - :current_password, # accessor: for updating pass - :profile_attributes, + :location, + :city, + :state_code, + :password_confirmation, # accessor: used on registration + :remember_me, # bool: don't sign user out for a while + :provider, # str: OAuth provider + :uid, # str: OAuth user ID + :pending_password, # bool: User registered with oauth and did not set a password + :name, # str: created with oauth + :auto_generated, # bool: flag whether a password was auto-generated for this account + :referer, # str: ID of the user who referred this account + :latitude, + :longitude, + :reset_password_token, + :reset_password_sent_at, + :picture, # str: url for fb or twitter pic + :current_password, # accessor: for updating pass + :profile_attributes, :phone - geocoded_by :location + geocoded_by :location - devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable, - :lockable + devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable, + :lockable - attr_accessor :offsite_donation_id, :current_password + attr_accessor :offsite_donation_id, :current_password - scope :nonprofit_admins, -> { includes(:roles).where("roles.name = 'nonprofit_admin'").references(:roles) } - scope :nonprofit_associates, -> { includes(:roles).where("roles.name = 'nonprofit_associate'").references(:roles) } - scope :nonprofit_personnel, -> {includes(:roles).where("roles.name = 'nonprofit_admin' OR roles.name='nonprofit_associate' ").references(:roles) } + scope :nonprofit_admins, -> { includes(:roles).where("roles.name = 'nonprofit_admin'").references(:roles) } + scope :nonprofit_associates, -> { includes(:roles).where("roles.name = 'nonprofit_associate'").references(:roles) } + scope :nonprofit_personnel, -> { includes(:roles).where("roles.name = 'nonprofit_admin' OR roles.name='nonprofit_associate' ").references(:roles) } - validates :email, - presence: true, - uniqueness: {case_sensitive: false}, - format: {with: Email::Regex} + validates :email, + presence: true, + uniqueness: {case_sensitive: false}, + format: {with: Email::Regex} - has_many :donations, through: :profile - has_many :roles, dependent: :destroy - has_one :profile, dependent: :destroy - has_many :imports + has_many :donations, through: :profile + has_many :roles, dependent: :destroy + has_one :profile, dependent: :destroy + has_many :imports has_many :email_settings has_and_belongs_to_many :periodic_reports - accepts_nested_attributes_for :profile + accepts_nested_attributes_for :profile - before_validation(on: :create) do - self.password = Devise.friendly_token.first(8) if self.auto_generated - self.build_profile if self.profile.nil? - self - end + before_validation(on: :create) do + self.password = Devise.friendly_token.first(8) if auto_generated + build_profile if profile.nil? + self + end # This creates the user in the normal way, but also sends the devise email confirmation email, which we don't want to send to np admins or anyone else def self.register_donor!(params) u = User.create!(params) u.send_confirmation_instructions - return u - end + u + end def self.find_or_create_with_email(em) - user = self.where("lower(email) = ?", em.downcase).first + user = where("lower(email) = ?", em.downcase).first return user if user.present? User.create!(email: em, auto_generated: true) end - def profile_picture(size) - self.profile.picture_url(size) - end - - - # Required by Devise for Omniauth - # https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview - def self.new_with_session(params, session) - super.tap do |user| - if data = session['devise.facebook_data'] && session['devise.facebook_data']['extra']['raw_info'] - user.email = data['email'] if user.email.blank? - end - end - end - - # Don't require confirmation for new users -- they can still donate without confirmation - # https://github.com/plataformatec/devise/wiki/How-To:-Override-confirmations-so-users-can-pick-their-own-passwords-as-part-of-confirmation-activation - def confirmation_required? - false - end - - # This lists the nonprofit_admin rules for the given user. There should only be one. - def nonprofit_admin_roles - roles.where(host_type: "Nonprofit").nonprofit_admins - end - - def as_json(options={}) - h = super(options) - h[:unconfirmed_email] = self.unconfirmed_email - h[:confirmed] = self.confirmed? - h[:profile] = self.profile.as_json - h - end + def profile_picture(size) + profile.picture_url(size) + end + + # Required by Devise for Omniauth + # https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview + def self.new_with_session(params, session) + super.tap do |user| + if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"] + user.email = data["email"] if user.email.blank? + end + end + end + + # Don't require confirmation for new users -- they can still donate without confirmation + # https://github.com/plataformatec/devise/wiki/How-To:-Override-confirmations-so-users-can-pick-their-own-passwords-as-part-of-confirmation-activation + def confirmation_required? + false + end + + # This lists the nonprofit_admin rules for the given user. There should only be one. + def nonprofit_admin_roles + roles.where(host_type: "Nonprofit").nonprofit_admins + end + + def as_json(options = {}) + h = super + h[:unconfirmed_email] = unconfirmed_email + h[:confirmed] = confirmed? + h[:profile] = profile.as_json + h + end # This is useful for manually generating a Devise user confirmation token so that we can get the confirmation URL with the correct token from anywhere def make_confirmation_token! raw, db = Devise.token_generator.generate(User, :confirmation_token) self.confirmation_token = db self.confirmation_sent_at = Time.now - self.save! - return raw + save! + raw + end + + # override the main devise_notification code because we're using Delayed::Job + def send_devise_notification(notification, *args) + devise_mailer.delay.send(notification, self, *args) end - - # override the main devise_notification code because we're using Delayed::Job - def send_devise_notification(notification, *args) - message = devise_mailer.delay.send(notification, self, *args) - end - - # override devise class method send_reset_password_instructions to limit to 1 request / 5 min - def self.send_reset_password_instructions(attributes={}) - recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found) - if recoverable.persisted? - if recoverable.reset_password_sent_at.nil? || Time.now > recoverable.reset_password_sent_at + 5.minutes + + # override devise class method send_reset_password_instructions to limit to 1 request / 5 min + def self.send_reset_password_instructions(attributes = {}) + recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found) + if recoverable.persisted? + if recoverable.reset_password_sent_at.nil? || Time.now > recoverable.reset_password_sent_at + 5.minutes recoverable.send_reset_password_instructions - return recoverable - else - recoverable.errors.add(:base, "can't reset password because a request was just sent") - end - end + return recoverable + else + recoverable.errors.add(:base, "can't reset password because a request was just sent") + end + end recoverable - end - - def geocode! - #self.geocode - #self.save - end + end + def geocode! + # self.geocode + # self.save + end end diff --git a/app/models/widget_description.rb b/app/models/widget_description.rb index a8740d6c1..c244893f0 100644 --- a/app/models/widget_description.rb +++ b/app/models/widget_description.rb @@ -9,13 +9,12 @@ class WidgetDescription < ApplicationRecord validate :is_postfix_element_a_hash, :is_postfix_element_correct - - validates_length_of :custom_amounts, minimum: 1, allow_nil:true + validates :custom_amounts, length: {minimum: 1, allow_nil: true} validate :are_custom_amounts_correct def to_json_safe_keys - attributes.slice('custom_amounts', 'postfix_element', 'custom_recurring_donation_phrase') + attributes.slice("custom_amounts", "postfix_element", "custom_recurring_donation_phrase") end private @@ -24,7 +23,7 @@ def are_custom_amounts_correct unless custom_amounts.nil? custom_amounts.each_with_index do |amount, index| if amount.is_a? Hash - unless (amount.has_key?('amount') && amount['amount'].is_a?(Integer)) + unless amount.has_key?("amount") && amount["amount"].is_a?(Integer) errors.add(:custom_amounts, "has an invalid amount #{amount} at index #{index}") end @@ -35,14 +34,13 @@ def are_custom_amounts_correct end end - def is_postfix_element_a_hash errors.add(:postfix_element, "must be a hash or nil") unless postfix_element.nil? || postfix_element.is_a?(Hash) end def is_postfix_element_correct if postfix_element.is_a? Hash - if !postfix_element.has_key?('type') || postfix_element['type'] != 'info' || !postfix_element.has_key?('html_content') + if !postfix_element.has_key?("type") || postfix_element["type"] != "info" || !postfix_element.has_key?("html_content") errors.add(:postfix_element, "has invalid contents") end end diff --git a/app/uploaders/article_background_uploader.rb b/app/uploaders/article_background_uploader.rb index 3fbaa3428..66796469b 100644 --- a/app/uploaders/article_background_uploader.rb +++ b/app/uploaders/article_background_uploader.rb @@ -2,7 +2,6 @@ # encoding: utf-8 class ArticleBackgroundUploader < CarrierWave::Uploader::Base - # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick @@ -20,7 +19,7 @@ def store_dir # Provide a default URL as a default if there hasn't been a file uploaded: def default_url # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultNonprofitUrl + Image::DefaultNonprofitUrl end # Process files as they are uploaded: @@ -32,14 +31,13 @@ def default_url # Create different versions of your uploaded files: version :large do - process :resize_to_fill => [600, 400] + process resize_to_fill: [600, 400] end - # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(jpg jpeg png) + %w[jpg jpeg png] end # Override the filename of the uploaded files: @@ -49,7 +47,6 @@ def extension_white_list # end def cache_dir - "#{Rails.root}/tmp/uploads" + "#{Rails.root.join("tmp/uploads")}" end - end diff --git a/app/uploaders/article_uploader.rb b/app/uploaders/article_uploader.rb index ac4b0d86e..bf288b50e 100644 --- a/app/uploaders/article_uploader.rb +++ b/app/uploaders/article_uploader.rb @@ -2,7 +2,6 @@ # encoding: utf-8 class ArticleUploader < CarrierWave::Uploader::Base - # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick @@ -20,7 +19,7 @@ def store_dir # Provide a default URL as a default if there hasn't been a file uploaded: def default_url # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultNonprofitUrl + Image::DefaultNonprofitUrl end # Process files as they are uploaded: @@ -32,13 +31,13 @@ def default_url # Create different versions of your uploaded files: version :thumb do - process :resize_to_fill => [200, 200] + process resize_to_fill: [200, 200] end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(jpg jpeg png) + %w[jpg jpeg png] end # Override the filename of the uploaded files: @@ -48,7 +47,6 @@ def extension_white_list # end def cache_dir - "#{Rails.root}/tmp/uploads" + "#{Rails.root.join("tmp/uploads")}" end - end diff --git a/app/uploaders/campaign_background_image_uploader.rb b/app/uploaders/campaign_background_image_uploader.rb index 57b6c6cba..00adc73a0 100644 --- a/app/uploaders/campaign_background_image_uploader.rb +++ b/app/uploaders/campaign_background_image_uploader.rb @@ -2,25 +2,22 @@ # encoding: utf-8 class CampaignBackgroundImageUploader < CarrierWave::Uploader::Base + include CarrierWave::MiniMagick - include CarrierWave::MiniMagick - + def store_dir + "uploads/campaigns/#{mounted_as}/#{model.id}" + end - def store_dir - "uploads/campaigns/#{mounted_as}/#{model.id}" - end + # Create different versions of your uploaded files: + version :normal do + process resize_to_fill: [1000, 600] + end - # Create different versions of your uploaded files: - version :normal do - process :resize_to_fill => [1000, 600] - end - - def extension_white_list - %w(jpg jpeg png) - end - - def cache_dir - "#{Rails.root}/tmp/uploads" - end + def extension_white_list + %w[jpg jpeg png] + end + def cache_dir + "#{Rails.root.join("tmp/uploads")}" + end end diff --git a/app/uploaders/campaign_banner_image_uploader.rb b/app/uploaders/campaign_banner_image_uploader.rb index 1c4010d74..0b6444752 100644 --- a/app/uploaders/campaign_banner_image_uploader.rb +++ b/app/uploaders/campaign_banner_image_uploader.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignBannerImageUploader < CarrierWave::Uploader::Base - include CarrierWave::MiniMagick + include CarrierWave::MiniMagick - def store_dir - "uploads/campaigns/#{mounted_as}/#{model.id}" - end + def store_dir + "uploads/campaigns/#{mounted_as}/#{model.id}" + end - def extension_white_list - %w(jpg jpeg png) - end + def extension_white_list + %w[jpg jpeg png] + end - def cache_dir - "#{Rails.root}/tmp/uploads" - end + def cache_dir + "#{Rails.root.join("tmp/uploads")}" + end end diff --git a/app/uploaders/campaign_main_image_uploader.rb b/app/uploaders/campaign_main_image_uploader.rb index bcf66cf18..687549ca2 100644 --- a/app/uploaders/campaign_main_image_uploader.rb +++ b/app/uploaders/campaign_main_image_uploader.rb @@ -1,56 +1,54 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class CampaignMainImageUploader < CarrierWave::Uploader::Base - - # Include RMagick or MiniMagick support: - # include CarrierWave::RMagick - include CarrierWave::MiniMagick - - # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: - # include Sprockets::Helpers::RailsHelper - # include Sprockets::Helpers::IsolatedHelper - - # Override the directory where uploaded files will be stored. - # This is a sensible default for uploaders that are meant to be mounted: - def store_dir - "uploads/campaigns/#{mounted_as}/#{model.id}" - end - - # Provide a default URL as a default if there hasn't been a file uploaded: - def default_url - # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultProfileUrl - end - - # Process files as they are uploaded: - # process :scale => [200, 300] - # - # def scale(width, height) - # # do something - # end - - # Create different versions of your uploaded files: - version :normal do - process :resize_to_fill => [524, 360] - end - - version :thumb do - process :resize_to_fill => [180, 150] - end - - # Add a white list of extensions which are allowed to be uploaded. - # For images you might use something like this: - def extension_white_list - %w(jpg jpeg png) - end - - # Override the filename of the uploaded files: - # Avoid using model.id or version_name here, see uploader/store.rb for details. - # def filename - # "something.jpg" if original_filename - # end - - def cache_dir - "#{Rails.root}/tmp/uploads" - end - + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: + # include Sprockets::Helpers::RailsHelper + # include Sprockets::Helpers::IsolatedHelper + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/campaigns/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + def default_url + # For Rails 3.1+ asset pipeline compatibility: + Image::DefaultProfileUrl + end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :normal do + process resize_to_fill: [524, 360] + end + + version :thumb do + process resize_to_fill: [180, 150] + end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w[jpg jpeg png] + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + + def cache_dir + "#{Rails.root.join("tmp/uploads")}" + end end diff --git a/app/uploaders/event_background_image_uploader.rb b/app/uploaders/event_background_image_uploader.rb index 02a304d27..9373f7e70 100644 --- a/app/uploaders/event_background_image_uploader.rb +++ b/app/uploaders/event_background_image_uploader.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EventBackgroundImageUploader < CarrierWave::Uploader::Base - # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick @@ -18,8 +17,8 @@ def store_dir # Provide a default URL as a default if there hasn't been a file uploaded: def default_url # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultCampaignUrl - end + Image::DefaultCampaignUrl + end # Process files as they are uploaded: # process :scale => [200, 300] @@ -30,13 +29,13 @@ def default_url # Create different versions of your uploaded files: version :normal do - process :resize_to_fill => [1000, 600] + process resize_to_fill: [1000, 600] end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(jpg jpeg png) + %w[jpg jpeg png] end # Override the filename of the uploaded files: @@ -46,7 +45,6 @@ def extension_white_list # end def cache_dir - "#{Rails.root}/tmp/uploads" + "#{Rails.root.join("tmp/uploads")}" end - end diff --git a/app/uploaders/event_main_image_uploader.rb b/app/uploaders/event_main_image_uploader.rb index 6afc1216c..b515556be 100644 --- a/app/uploaders/event_main_image_uploader.rb +++ b/app/uploaders/event_main_image_uploader.rb @@ -1,56 +1,54 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class EventMainImageUploader < CarrierWave::Uploader::Base - - # Include RMagick or MiniMagick support: - # include CarrierWave::RMagick - include CarrierWave::MiniMagick - - # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: - # include Sprockets::Helpers::RailsHelper - # include Sprockets::Helpers::IsolatedHelper - - # Override the directory where uploaded files will be stored. - # This is a sensible default for uploaders that are meant to be mounted: - def store_dir - "uploads/events/#{mounted_as}/#{model.id}" - end - - # Provide a default URL as a default if there hasn't been a file uploaded: - def default_url - # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultProfileUrl - end - - # Process files as they are uploaded: - # process :scale => [200, 300] - # - # def scale(width, height) - # # do something - # end - - # Create different versions of your uploaded files: - version :normal do - process :resize_to_fill => [400, 400] - end - - version :thumb do - process :resize_to_fill => [100,100] - end - - # Add a white list of extensions which are allowed to be uploaded. - # For images you might use something like this: - def extension_white_list - %w(jpg jpeg png) - end - - # Override the filename of the uploaded files: - # Avoid using model.id or version_name here, see uploader/store.rb for details. - # def filename - # "something.jpg" if original_filename - # end - - def cache_dir - "#{Rails.root}/tmp/uploads" - end - + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: + # include Sprockets::Helpers::RailsHelper + # include Sprockets::Helpers::IsolatedHelper + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/events/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + def default_url + # For Rails 3.1+ asset pipeline compatibility: + Image::DefaultProfileUrl + end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :normal do + process resize_to_fill: [400, 400] + end + + version :thumb do + process resize_to_fill: [100, 100] + end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w[jpg jpeg png] + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + + def cache_dir + "#{Rails.root.join("tmp/uploads")}" + end end diff --git a/app/uploaders/image_attachment_uploader.rb b/app/uploaders/image_attachment_uploader.rb index 01b644f65..da05bc92b 100644 --- a/app/uploaders/image_attachment_uploader.rb +++ b/app/uploaders/image_attachment_uploader.rb @@ -2,7 +2,6 @@ # encoding: utf-8 class ImageAttachmentUploader < CarrierWave::Uploader::Base - # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick @@ -20,8 +19,8 @@ def store_dir # Provide a default URL as a default if there hasn't been a file uploaded: def default_url # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultProfileUrl - end + Image::DefaultProfileUrl + end # Process files as they are uploaded: # process :scale => [200, 300] @@ -32,23 +31,23 @@ def default_url # Create different versions of your uploaded files: version :large do - process :resize_to_fill => [600, 400] + process resize_to_fill: [600, 400] end version :medium do - process :resize_to_fill => [400, 266] + process resize_to_fill: [400, 266] end version :small do - process :resize_to_fill => [400, 266] + process resize_to_fill: [400, 266] end # slightly smaller than the normal thumb version :thumb_explore do - process :resize_to_fill => [200, 133] + process resize_to_fill: [200, 133] end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(jpg jpeg png) + %w[jpg jpeg png] end # Override the filename of the uploaded files: @@ -58,7 +57,6 @@ def extension_white_list # end def cache_dir - "#{Rails.root}/tmp/uploads" + "#{Rails.root.join("tmp/uploads")}" end - end diff --git a/app/uploaders/nonprofit_background_uploader.rb b/app/uploaders/nonprofit_background_uploader.rb index b46f6284b..5f4327bc4 100644 --- a/app/uploaders/nonprofit_background_uploader.rb +++ b/app/uploaders/nonprofit_background_uploader.rb @@ -3,7 +3,6 @@ # encoding: utf-8 class NonprofitBackgroundUploader < CarrierWave::Uploader::Base - # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick @@ -21,8 +20,8 @@ def store_dir # Provide a default URL as a default if there hasn't been a file uploaded: def default_url # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultNonprofitUrl - end + Image::DefaultNonprofitUrl + end # Process files as they are uploaded: # process :scale => [200, 300] @@ -33,13 +32,13 @@ def default_url # Create different versions of your uploaded files: version :normal do - process :resize_to_fill => [1000, 600] + process resize_to_fill: [1000, 600] end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(jpg jpeg png) + %w[jpg jpeg png] end # Override the filename of the uploaded files: @@ -49,7 +48,6 @@ def extension_white_list # end def cache_dir - "#{Rails.root}/tmp/uploads" + "#{Rails.root.join("tmp/uploads")}" end - end diff --git a/app/uploaders/nonprofit_logo_uploader.rb b/app/uploaders/nonprofit_logo_uploader.rb index c068b73c6..78fdeae77 100644 --- a/app/uploaders/nonprofit_logo_uploader.rb +++ b/app/uploaders/nonprofit_logo_uploader.rb @@ -2,50 +2,48 @@ # encoding: utf-8 class NonprofitLogoUploader < CarrierWave::Uploader::Base - - # Include RMagick or MiniMagick support: - # include CarrierWave::RMagick - include CarrierWave::MiniMagick - - # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: - # include Sprockets::Helpers::RailsHelper - # include Sprockets::Helpers::IsolatedHelper - - # Override the directory where uploaded files will be stored. - # This is a sensible default for uploaders that are meant to be mounted: - def store_dir - "uploads/npo/#{mounted_as}/#{model.id}" - end - - # Provide a default URL as a default if there hasn't been a file uploaded: - def default_url - # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultProfileUrl - end - - # Create different versions of your uploaded files: - version :large do - process :resize_to_fit => [180, 180] - end - version :normal do - process :resize_to_fit => [100, 100] - end - version :small do - process :resize_to_fit => [30, 30] - end - - def extension_white_list - %w(jpg jpeg png gif) - end - - # Override the filename of the uploaded files: - # Avoid using model.id or version_name here, see uploader/store.rb for details. - # def filename - # "something.jpg" if original_filename - # end - - def cache_dir - "#{Rails.root}/tmp/uploads" - end - + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: + # include Sprockets::Helpers::RailsHelper + # include Sprockets::Helpers::IsolatedHelper + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/npo/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + def default_url + # For Rails 3.1+ asset pipeline compatibility: + Image::DefaultProfileUrl + end + + # Create different versions of your uploaded files: + version :large do + process resize_to_fit: [180, 180] + end + version :normal do + process resize_to_fit: [100, 100] + end + version :small do + process resize_to_fit: [30, 30] + end + + def extension_white_list + %w[jpg jpeg png gif] + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + + def cache_dir + "#{Rails.root.join("tmp/uploads")}" + end end diff --git a/app/uploaders/nonprofit_uploader.rb b/app/uploaders/nonprofit_uploader.rb index fe37a30c4..3d8408253 100755 --- a/app/uploaders/nonprofit_uploader.rb +++ b/app/uploaders/nonprofit_uploader.rb @@ -2,7 +2,6 @@ # encoding: utf-8 class NonprofitUploader < CarrierWave::Uploader::Base - # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick @@ -20,7 +19,7 @@ def store_dir # Provide a default URL as a default if there hasn't been a file uploaded: def default_url # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultProfileUrl + Image::DefaultProfileUrl end # Process files as they are uploaded: @@ -32,20 +31,20 @@ def default_url # Create different versions of your uploaded files: version :nonprofit_carousel do - process :resize_to_fill => [590, 338] + process resize_to_fill: [590, 338] end version :thumb do - process :resize_to_fill => [188, 120] + process resize_to_fill: [188, 120] end # slightly smaller than the normal thumb version :thumb_explore do - process :resize_to_fill => [100, 100] + process resize_to_fill: [100, 100] end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: def extension_white_list - %w(jpg jpeg png) + %w[jpg jpeg png] end # Override the filename of the uploaded files: @@ -55,7 +54,6 @@ def extension_white_list # end def cache_dir - "#{Rails.root}/tmp/uploads" + "#{Rails.root.join("tmp/uploads")}" end - end diff --git a/app/uploaders/profile_uploader.rb b/app/uploaders/profile_uploader.rb index ec911fd4d..e1e5b8e8c 100644 --- a/app/uploaders/profile_uploader.rb +++ b/app/uploaders/profile_uploader.rb @@ -2,59 +2,57 @@ # encoding: utf-8 class ProfileUploader < CarrierWave::Uploader::Base - - # Include RMagick or MiniMagick support: - # include CarrierWave::RMagick - include CarrierWave::MiniMagick - - # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: - # include Sprockets::Helpers::RailsHelper - # include Sprockets::Helpers::IsolatedHelper - - # Override the directory where uploaded files will be stored. - # This is a sensible default for uploaders that are meant to be mounted: - def store_dir - "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" - end - - # Provide a default URL as a default if there hasn't been a file uploaded: - def default_url - # For Rails 3.1+ asset pipeline compatibility: - return Image::DefaultProfileUrl - end - - # Process files as they are uploaded: - # process :scale => [200, 300] - # - # def scale(width, height) - # # do something - # end - - # Create different versions of your uploaded files: - version :normal do - process :resize_to_fill => [150, 150] - end - version :medium do - process :resize_to_fill => [100, 100] - end - version :tiny do - process :resize_to_fill => [50, 50] - end - - # Add a white list of extensions which are allowed to be uploaded. - # For images you might use something like this: - def extension_white_list - %w(jpg jpeg png) - end - - # Override the filename of the uploaded files: - # Avoid using model.id or version_name here, see uploader/store.rb for details. - # def filename - # "something.jpg" if original_filename - # end - - def cache_dir - "#{Rails.root}/tmp/uploads" - end - + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + include CarrierWave::MiniMagick + + # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: + # include Sprockets::Helpers::RailsHelper + # include Sprockets::Helpers::IsolatedHelper + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + def default_url + # For Rails 3.1+ asset pipeline compatibility: + Image::DefaultProfileUrl + end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + version :normal do + process resize_to_fill: [150, 150] + end + version :medium do + process resize_to_fill: [100, 100] + end + version :tiny do + process resize_to_fill: [50, 50] + end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + def extension_white_list + %w[jpg jpeg png] + end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + + def cache_dir + "#{Rails.root.join("tmp/uploads")}" + end end diff --git a/app/validators/postgresql_date_format_validator.rb b/app/validators/postgresql_date_format_validator.rb index 33b3ce790..7f61dc8ea 100644 --- a/app/validators/postgresql_date_format_validator.rb +++ b/app/validators/postgresql_date_format_validator.rb @@ -4,8 +4,8 @@ class PostgresqlDateFormatValidator < ActiveModel::Validator # must receive a { options: { attribute_name: } } to do the validation def validate(record) date_format = record[options[:attribute_name]] - unless (date_format.nil? || valid_date_format?(date_format)) - record.errors.add(:date_format, 'invalid date format') + unless date_format.nil? || valid_date_format?(date_format) + record.errors.add(:date_format, "invalid date format") end end @@ -13,7 +13,7 @@ def validate(record) def valid_date_format?(date_format) ALLOWED_SEPARATORS.each do |separator| - date_format = (date_format.split(separator)).flatten + date_format = date_format.split(separator).flatten end date_format.each do |date_pattern_element| return false unless ALLOWED_POSTGRES_PATTERNS.include?(date_pattern_element) @@ -21,14 +21,14 @@ def valid_date_format?(date_format) true end - ALLOWED_SEPARATORS = ['/', '-', '.', ':'].freeze + ALLOWED_SEPARATORS = ["/", "-", ".", ":"].freeze ALLOWED_POSTGRES_PATTERNS = [ - 'HH', 'HH12', 'HH24', 'MI', 'SS', 'MS', 'US', 'FF1', 'FF2', 'FF3', 'FF4', 'FF5', 'FF6', - 'SSSS', 'SSSSS', 'AM', 'am', 'PM', 'pm', 'A.M.', 'a.m.', 'P.M.', 'p.m.', 'Y', 'YYYY', 'YYY', - 'YY', 'Y', 'IYYY', 'IYY', 'IY', 'I', 'BC', 'bc', 'AD', 'ad', 'B.C.', 'b.c.', 'A.D.', 'a.d.', - 'MONTH', 'Month', 'month', 'MON', 'Mon', 'mon', 'MM', 'DAY', 'Day', 'day', 'DY', 'Dy', 'dy', - 'DDD', 'IDDD', 'DD', 'D', 'ID', 'W', 'WW', 'IW', 'CC', 'J', 'Q', 'RM', 'rm', 'TZ', 'tz', - 'TZH', 'TZM', 'OF' + "HH", "HH12", "HH24", "MI", "SS", "MS", "US", "FF1", "FF2", "FF3", "FF4", "FF5", "FF6", + "SSSS", "SSSSS", "AM", "am", "PM", "pm", "A.M.", "a.m.", "P.M.", "p.m.", "Y", "YYYY", "YYY", + "YY", "Y", "IYYY", "IYY", "IY", "I", "BC", "bc", "AD", "ad", "B.C.", "b.c.", "A.D.", "a.d.", + "MONTH", "Month", "month", "MON", "Mon", "mon", "MM", "DAY", "Day", "day", "DY", "Dy", "dy", + "DDD", "IDDD", "DD", "D", "ID", "W", "WW", "IW", "CC", "J", "Q", "RM", "rm", "TZ", "tz", + "TZH", "TZM", "OF" ].freeze end diff --git a/app/views/api_new/common/_amount.json.jbuilder b/app/views/api_new/common/_amount.json.jbuilder index 0420ea824..1215c2146 100644 --- a/app/views/api_new/common/_amount.json.jbuilder +++ b/app/views/api_new/common/_amount.json.jbuilder @@ -3,4 +3,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.(amount, :cents, :currency) +json.call(amount, :cents, :currency) diff --git a/app/views/api_new/modern_donations/_modern_donation.json.jbuilder b/app/views/api_new/modern_donations/_modern_donation.json.jbuilder index 9356af24a..b425a7f7b 100644 --- a/app/views/api_new/modern_donations/_modern_donation.json.jbuilder +++ b/app/views/api_new/modern_donations/_modern_donation.json.jbuilder @@ -3,11 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'donation' +json.object "donation" - -json.(assignable, :designation, :legacy_id, :dedication, :comment) +json.call(assignable, :designation, :legacy_id, :dedication, :comment) json.amount do - json.partial! '/api_new/common/amount', amount: assignable.amount_as_money + json.partial! "/api_new/common/amount", amount: assignable.amount_as_money end diff --git a/app/views/api_new/modern_donations/object_events/_base.json.jbuilder b/app/views/api_new/modern_donations/object_events/_base.json.jbuilder index 4c5f983f1..697e64756 100644 --- a/app/views/api_new/modern_donations/object_events/_base.json.jbuilder +++ b/app/views/api_new/modern_donations/object_events/_base.json.jbuilder @@ -3,10 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/transaction_assignments/transaction_assignment', +json.partial! "api_new/transaction_assignments/transaction_assignment", transaction_assignment: event_entity.transaction_assignment, __expand: build_json_expansion_path_tree( - 'transaction', - 'transaction.transaction_assignments', - 'transaction.subtransaction.payments' - ) \ No newline at end of file + "transaction", + "transaction.transaction_assignments", + "transaction.subtransaction.payments" + ) diff --git a/app/views/api_new/object_events/_object_event.json.jbuilder b/app/views/api_new/object_events/_object_event.json.jbuilder index 9d0ba3c5c..430ed5d97 100644 --- a/app/views/api_new/object_events/_object_event.json.jbuilder +++ b/app/views/api_new/object_events/_object_event.json.jbuilder @@ -1,4 +1,3 @@ - # frozen_string_literal: true # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later @@ -6,10 +5,10 @@ json.id object_event.houid json.created object_event.created.to_i -json.object 'object_event' +json.object "object_event" json.type object_event.event_type json.data do json.object do json.partial! partial_path, event_entity: object_event.event_entity end -end \ No newline at end of file +end diff --git a/app/views/api_new/object_events/index.json.jbuilder b/app/views/api_new/object_events/index.json.jbuilder index 3fb0e5ebe..e4361c3f2 100644 --- a/app/views/api_new/object_events/index.json.jbuilder +++ b/app/views/api_new/object_events/index.json.jbuilder @@ -2,12 +2,12 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.data do +json.data do json.array! @object_events.map(&:object_json) end json.current_page @object_events.current_page json.first_page @object_events.first_page? -json.last_page@object_events.last_page? +json.last_page @object_events.last_page? json.requested_size @object_events.limit_value -json.total_count @object_events.total_count \ No newline at end of file +json.total_count @object_events.total_count diff --git a/app/views/api_new/offline_transaction_charges/_offline_transaction_charge.json.jbuilder b/app/views/api_new/offline_transaction_charges/_offline_transaction_charge.json.jbuilder index b68b55bbe..438f96783 100644 --- a/app/views/api_new/offline_transaction_charges/_offline_transaction_charge.json.jbuilder +++ b/app/views/api_new/offline_transaction_charges/_offline_transaction_charge.json.jbuilder @@ -3,7 +3,7 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'offline_transaction_charge' +json.object "offline_transaction_charge" json.created paymentable.created.to_i @@ -11,13 +11,13 @@ json.kind paymentable.subtransaction_payment.legacy_payment.offsite_payment&.kin json.check_number paymentable.subtransaction_payment.legacy_payment.offsite_payment&.check_number json.net_amount do - json.partial! '/api_new/common/amount', amount: paymentable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.net_amount_as_money end json.gross_amount do - json.partial! '/api_new/common/amount', amount: paymentable.gross_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.gross_amount_as_money end json.fee_total do - json.partial! '/api_new/common/amount', amount: paymentable.fee_total_as_money + json.partial! "/api_new/common/amount", amount: paymentable.fee_total_as_money end diff --git a/app/views/api_new/offline_transaction_charges/object_events/_base.json.jbuilder b/app/views/api_new/offline_transaction_charges/object_events/_base.json.jbuilder index bc2e74153..809f9a671 100644 --- a/app/views/api_new/offline_transaction_charges/object_events/_base.json.jbuilder +++ b/app/views/api_new/offline_transaction_charges/object_events/_base.json.jbuilder @@ -3,11 +3,11 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/subtransaction_payments/subtransaction_payment', +json.partial! "api_new/subtransaction_payments/subtransaction_payment", subtransaction_payment: event_entity.subtransaction_payment, __expand: build_json_expansion_path_tree( - 'supporter', - 'subtransaction', - 'subtransaction.transaction', - 'subtransaction.transaction.transaction_assignments' + "supporter", + "subtransaction", + "subtransaction.transaction", + "subtransaction.transaction.transaction_assignments" ) diff --git a/app/views/api_new/offline_transaction_charges/show.json.jbuilder b/app/views/api_new/offline_transaction_charges/show.json.jbuilder index ed2bfc958..d14c75506 100644 --- a/app/views/api_new/offline_transaction_charges/show.json.jbuilder +++ b/app/views/api_new/offline_transaction_charges/show.json.jbuilder @@ -1,4 +1,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! '/api_new/offline_transaction_charges/offline_transaction_charge', paymentable: @offline_transaction_charge +json.partial! "/api_new/offline_transaction_charges/offline_transaction_charge", paymentable: @offline_transaction_charge diff --git a/app/views/api_new/offline_transactions/_offline_transaction.json.jbuilder b/app/views/api_new/offline_transactions/_offline_transaction.json.jbuilder index 0751c12d4..3be9890a3 100644 --- a/app/views/api_new/offline_transactions/_offline_transaction.json.jbuilder +++ b/app/views/api_new/offline_transactions/_offline_transaction.json.jbuilder @@ -3,14 +3,14 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'offline_transaction' +json.object "offline_transaction" json.created subtransactable.created.to_i json.amount do - json.partial! '/api_new/common/amount', amount: subtransactable.amount_as_money + json.partial! "/api_new/common/amount", amount: subtransactable.amount_as_money end json.net_amount do - json.partial! '/api_new/common/amount', amount: subtransactable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: subtransactable.net_amount_as_money end diff --git a/app/views/api_new/payouts/_payout.json.jbuilder b/app/views/api_new/payouts/_payout.json.jbuilder index 564719b52..b47ebe0b5 100644 --- a/app/views/api_new/payouts/_payout.json.jbuilder +++ b/app/views/api_new/payouts/_payout.json.jbuilder @@ -4,12 +4,12 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE json.id payout.houid -json.object 'payout' +json.object "payout" json.created payout.created_at.to_i json.net_amount do - json.partial! '/api_new/common/amount', amount: payout.net_amount_as_money + json.partial! "/api_new/common/amount", amount: payout.net_amount_as_money end json.status payout.status diff --git a/app/views/api_new/payouts/object_events/_base.json.jbuilder b/app/views/api_new/payouts/object_events/_base.json.jbuilder index 5ade46412..f99f2912f 100644 --- a/app/views/api_new/payouts/object_events/_base.json.jbuilder +++ b/app/views/api_new/payouts/object_events/_base.json.jbuilder @@ -3,5 +3,5 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/payouts/payout', +json.partial! "api_new/payouts/payout", payout: event_entity diff --git a/app/views/api_new/payouts/show.json.jbuilder b/app/views/api_new/payouts/show.json.jbuilder index d00e3d77b..f61b33034 100644 --- a/app/views/api_new/payouts/show.json.jbuilder +++ b/app/views/api_new/payouts/show.json.jbuilder @@ -3,4 +3,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! '/api_new/payouts/payout', payout: @payout \ No newline at end of file +json.partial! "/api_new/payouts/payout", payout: @payout diff --git a/app/views/api_new/simple_objects/_simple_object.json.jbuilder b/app/views/api_new/simple_objects/_simple_object.json.jbuilder index 904382ae3..3870cf510 100644 --- a/app/views/api_new/simple_objects/_simple_object.json.jbuilder +++ b/app/views/api_new/simple_objects/_simple_object.json.jbuilder @@ -5,7 +5,7 @@ json.id object.houid -json.object 'simple_object' +json.object "simple_object" handle_expansion(:parent, object.parent, {json: json, as: :object, __expand: __expand}) diff --git a/app/views/api_new/simple_objects/object_events/_base.json.jbuilder b/app/views/api_new/simple_objects/object_events/_base.json.jbuilder index 2e006313b..17f2d12e2 100644 --- a/app/views/api_new/simple_objects/object_events/_base.json.jbuilder +++ b/app/views/api_new/simple_objects/object_events/_base.json.jbuilder @@ -3,4 +3,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! event_entity, as: :object, __expand: build_json_expansion_path_tree('parent') \ No newline at end of file +json.partial! event_entity, as: :object, __expand: build_json_expansion_path_tree("parent") diff --git a/app/views/api_new/simple_objects/show.json.jbuilder b/app/views/api_new/simple_objects/show.json.jbuilder index 85877155c..0067f30c4 100644 --- a/app/views/api_new/simple_objects/show.json.jbuilder +++ b/app/views/api_new/simple_objects/show.json.jbuilder @@ -1 +1 @@ -json.partial! @simple_object, as: :object, __expand: @__expand \ No newline at end of file +json.partial! @simple_object, as: :object, __expand: @__expand diff --git a/app/views/api_new/stripe_transaction_charges/_stripe_transaction_charge.json.jbuilder b/app/views/api_new/stripe_transaction_charges/_stripe_transaction_charge.json.jbuilder index 4c11ebfd5..289447c7e 100644 --- a/app/views/api_new/stripe_transaction_charges/_stripe_transaction_charge.json.jbuilder +++ b/app/views/api_new/stripe_transaction_charges/_stripe_transaction_charge.json.jbuilder @@ -3,16 +3,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'stripe_transaction_charge' +json.object "stripe_transaction_charge" json.net_amount do - json.partial! '/api_new/common/amount', amount: paymentable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.net_amount_as_money end json.gross_amount do - json.partial! '/api_new/common/amount', amount: paymentable.gross_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.gross_amount_as_money end json.fee_total do - json.partial! '/api_new/common/amount', amount: paymentable.fee_total_as_money + json.partial! "/api_new/common/amount", amount: paymentable.fee_total_as_money end diff --git a/app/views/api_new/stripe_transaction_charges/object_events/_base.json.jbuilder b/app/views/api_new/stripe_transaction_charges/object_events/_base.json.jbuilder index 106811ee3..e0a8e29a4 100644 --- a/app/views/api_new/stripe_transaction_charges/object_events/_base.json.jbuilder +++ b/app/views/api_new/stripe_transaction_charges/object_events/_base.json.jbuilder @@ -3,10 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/subtransaction_payments/subtransaction_payment', +json.partial! "api_new/subtransaction_payments/subtransaction_payment", subtransaction_payment: event_entity.subtransaction_payment, __expand: build_json_expansion_path_tree( - 'supporter', - 'subtransaction.payments', - 'subtransaction.transaction.transaction_assignments' - ) \ No newline at end of file + "supporter", + "subtransaction.payments", + "subtransaction.transaction.transaction_assignments" + ) diff --git a/app/views/api_new/stripe_transaction_dispute_reversals/_stripe_transaction_dispute_reversal.json.jbuilder b/app/views/api_new/stripe_transaction_dispute_reversals/_stripe_transaction_dispute_reversal.json.jbuilder index 0f51e753c..83b20b523 100644 --- a/app/views/api_new/stripe_transaction_dispute_reversals/_stripe_transaction_dispute_reversal.json.jbuilder +++ b/app/views/api_new/stripe_transaction_dispute_reversals/_stripe_transaction_dispute_reversal.json.jbuilder @@ -3,16 +3,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'stripe_transaction_dispute_reversal' +json.object "stripe_transaction_dispute_reversal" json.net_amount do - json.partial! '/api_new/common/amount', amount: paymentable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.net_amount_as_money end json.gross_amount do - json.partial! '/api_new/common/amount', amount: paymentable.gross_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.gross_amount_as_money end json.fee_total do - json.partial! '/api_new/common/amount', amount: paymentable.fee_total_as_money + json.partial! "/api_new/common/amount", amount: paymentable.fee_total_as_money end diff --git a/app/views/api_new/stripe_transaction_dispute_reversals/object_events/_base.json.jbuilder b/app/views/api_new/stripe_transaction_dispute_reversals/object_events/_base.json.jbuilder index f123bb942..809f9a671 100644 --- a/app/views/api_new/stripe_transaction_dispute_reversals/object_events/_base.json.jbuilder +++ b/app/views/api_new/stripe_transaction_dispute_reversals/object_events/_base.json.jbuilder @@ -3,11 +3,11 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/subtransaction_payments/subtransaction_payment', +json.partial! "api_new/subtransaction_payments/subtransaction_payment", subtransaction_payment: event_entity.subtransaction_payment, __expand: build_json_expansion_path_tree( - 'supporter', - 'subtransaction', - 'subtransaction.transaction', - 'subtransaction.transaction.transaction_assignments' - ) \ No newline at end of file + "supporter", + "subtransaction", + "subtransaction.transaction", + "subtransaction.transaction.transaction_assignments" + ) diff --git a/app/views/api_new/stripe_transaction_disputes/_stripe_transaction_dispute.json.jbuilder b/app/views/api_new/stripe_transaction_disputes/_stripe_transaction_dispute.json.jbuilder index 01db54d26..ed4bbf525 100644 --- a/app/views/api_new/stripe_transaction_disputes/_stripe_transaction_dispute.json.jbuilder +++ b/app/views/api_new/stripe_transaction_disputes/_stripe_transaction_dispute.json.jbuilder @@ -3,16 +3,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'stripe_transaction_dispute' +json.object "stripe_transaction_dispute" json.net_amount do - json.partial! '/api_new/common/amount', amount: paymentable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.net_amount_as_money end json.gross_amount do - json.partial! '/api_new/common/amount', amount: paymentable.gross_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.gross_amount_as_money end json.fee_total do - json.partial! '/api_new/common/amount', amount: paymentable.fee_total_as_money + json.partial! "/api_new/common/amount", amount: paymentable.fee_total_as_money end diff --git a/app/views/api_new/stripe_transaction_disputes/object_events/_base.json.jbuilder b/app/views/api_new/stripe_transaction_disputes/object_events/_base.json.jbuilder index 2889bf3fb..ea58f1be7 100644 --- a/app/views/api_new/stripe_transaction_disputes/object_events/_base.json.jbuilder +++ b/app/views/api_new/stripe_transaction_disputes/object_events/_base.json.jbuilder @@ -3,10 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/subtransaction_payments/subtransaction_payment', +json.partial! "api_new/subtransaction_payments/subtransaction_payment", subtransaction_payment: event_entity.subtransaction_payment, __expand: build_json_expansion_path_tree( - 'supporter', - 'subtransaction.transaction', - 'subtransaction.transaction.transaction_assignments' - ) \ No newline at end of file + "supporter", + "subtransaction.transaction", + "subtransaction.transaction.transaction_assignments" + ) diff --git a/app/views/api_new/stripe_transaction_refunds/_stripe_transaction_refund.json.jbuilder b/app/views/api_new/stripe_transaction_refunds/_stripe_transaction_refund.json.jbuilder index 7c1478ac9..0b2465394 100644 --- a/app/views/api_new/stripe_transaction_refunds/_stripe_transaction_refund.json.jbuilder +++ b/app/views/api_new/stripe_transaction_refunds/_stripe_transaction_refund.json.jbuilder @@ -3,16 +3,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'stripe_transaction_refund' +json.object "stripe_transaction_refund" json.net_amount do - json.partial! '/api_new/common/amount', amount: paymentable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.net_amount_as_money end json.gross_amount do - json.partial! '/api_new/common/amount', amount: paymentable.gross_amount_as_money + json.partial! "/api_new/common/amount", amount: paymentable.gross_amount_as_money end json.fee_total do - json.partial! '/api_new/common/amount', amount: paymentable.fee_total_as_money + json.partial! "/api_new/common/amount", amount: paymentable.fee_total_as_money end diff --git a/app/views/api_new/stripe_transaction_refunds/object_events/_base.json.jbuilder b/app/views/api_new/stripe_transaction_refunds/object_events/_base.json.jbuilder index f123bb942..809f9a671 100644 --- a/app/views/api_new/stripe_transaction_refunds/object_events/_base.json.jbuilder +++ b/app/views/api_new/stripe_transaction_refunds/object_events/_base.json.jbuilder @@ -3,11 +3,11 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/subtransaction_payments/subtransaction_payment', +json.partial! "api_new/subtransaction_payments/subtransaction_payment", subtransaction_payment: event_entity.subtransaction_payment, __expand: build_json_expansion_path_tree( - 'supporter', - 'subtransaction', - 'subtransaction.transaction', - 'subtransaction.transaction.transaction_assignments' - ) \ No newline at end of file + "supporter", + "subtransaction", + "subtransaction.transaction", + "subtransaction.transaction.transaction_assignments" + ) diff --git a/app/views/api_new/stripe_transactions/_stripe_transaction.json.jbuilder b/app/views/api_new/stripe_transactions/_stripe_transaction.json.jbuilder index 225ce91fa..c1994d3e7 100644 --- a/app/views/api_new/stripe_transactions/_stripe_transaction.json.jbuilder +++ b/app/views/api_new/stripe_transactions/_stripe_transaction.json.jbuilder @@ -3,14 +3,14 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'stripe_transaction' +json.object "stripe_transaction" json.created subtransactable.created.to_i json.amount do - json.partial! '/api_new/common/amount', amount: subtransactable.amount_as_money + json.partial! "/api_new/common/amount", amount: subtransactable.amount_as_money end json.net_amount do - json.partial! '/api_new/common/amount', amount: subtransactable.net_amount_as_money + json.partial! "/api_new/common/amount", amount: subtransactable.net_amount_as_money end diff --git a/app/views/api_new/subtransaction_payments/_subtransaction_payment.json.jbuilder b/app/views/api_new/subtransaction_payments/_subtransaction_payment.json.jbuilder index ffe5281a5..33a76cf4d 100644 --- a/app/views/api_new/subtransaction_payments/_subtransaction_payment.json.jbuilder +++ b/app/views/api_new/subtransaction_payments/_subtransaction_payment.json.jbuilder @@ -2,7 +2,7 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.type 'payment' +json.type "payment" json.id subtransaction_payment.paymentable.houid json.created subtransaction_payment.created.to_i @@ -12,7 +12,7 @@ json.legacy_id subtransaction_payment.legacy_payment_id json.legacy_nonprofit subtransaction_payment.nonprofit.id handle_expansion(:supporter, subtransaction_payment.supporter, {json: json, __expand: __expand}) -handle_expansion(:nonprofit, subtransaction_payment.nonprofit, {json: json, __expand: __expand}) +handle_expansion(:nonprofit, subtransaction_payment.nonprofit, {json: json, __expand: __expand}) handle_expansion(:transaction, subtransaction_payment.trx, {json: json, __expand: __expand}) handle_expansion(:subtransaction, subtransaction_payment.subtransaction, {json: json, __expand: __expand}) diff --git a/app/views/api_new/subtransactions/_subtransaction.json.jbuilder b/app/views/api_new/subtransactions/_subtransaction.json.jbuilder index cc1a3d551..175350058 100644 --- a/app/views/api_new/subtransactions/_subtransaction.json.jbuilder +++ b/app/views/api_new/subtransactions/_subtransaction.json.jbuilder @@ -4,17 +4,16 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE json.id subtransaction.to_houid -json.type 'subtransaction' +json.type "subtransaction" json.created subtransaction.created.to_i handle_expansion(:supporter, subtransaction.supporter, {json: json, __expand: __expand}) -handle_expansion(:nonprofit, subtransaction.nonprofit, {json: json, __expand: __expand}) +handle_expansion(:nonprofit, subtransaction.nonprofit, {json: json, __expand: __expand}) handle_expansion(:transaction, subtransaction.trx, {json: json, __expand: __expand}) -handle_array_expansion(:payments, subtransaction.subtransaction_payments.ordered, {json:json, __expand: __expand, item_as: :subtransaction_payment}) do |expansion| +handle_array_expansion(:payments, subtransaction.subtransaction_payments.ordered, {json: json, __expand: __expand, item_as: :subtransaction_payment}) do |expansion| expansion.handle_item_expansion end - json.partial! subtransaction.subtransactable, as: :subtransactable, __expand: __expand diff --git a/app/views/api_new/supporters/_supporter.json.jbuilder b/app/views/api_new/supporters/_supporter.json.jbuilder index 2ed35a7c8..c62e1daae 100644 --- a/app/views/api_new/supporters/_supporter.json.jbuilder +++ b/app/views/api_new/supporters/_supporter.json.jbuilder @@ -3,11 +3,11 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.(supporter, :name, :email, :organization, :phone, :anonymous, :deleted) +json.call(supporter, :name, :email, :organization, :phone, :anonymous, :deleted) json.id supporter.houid -json.object 'supporter' +json.object "supporter" json.merged_into supporter.merged_into&.houid @@ -22,6 +22,6 @@ end json.legacy_id supporter.id json.legacy_nonprofit supporter.nonprofit_id -#json.url api_new_nonprofit_supporter_url(supporter.nonprofit.to_modern_param, supporter.to_modern_param) +# json.url api_new_nonprofit_supporter_url(supporter.nonprofit.to_modern_param, supporter.to_modern_param) json.nonprofit supporter.nonprofit.houid diff --git a/app/views/api_new/supporters/index.json.jbuilder b/app/views/api_new/supporters/index.json.jbuilder index f95c6c7b8..64c9b3d52 100644 --- a/app/views/api_new/supporters/index.json.jbuilder +++ b/app/views/api_new/supporters/index.json.jbuilder @@ -2,7 +2,7 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.data @supporters, partial: '/api_new/supporters/supporter', as: :supporter +json.data @supporters, partial: "/api_new/supporters/supporter", as: :supporter json.current_page @supporters.current_page json.first_page @supporters.first_page? diff --git a/app/views/api_new/supporters/object_events/_base.json.jbuilder b/app/views/api_new/supporters/object_events/_base.json.jbuilder index cbc981d08..cec2da6fe 100644 --- a/app/views/api_new/supporters/object_events/_base.json.jbuilder +++ b/app/views/api_new/supporters/object_events/_base.json.jbuilder @@ -1,4 +1,4 @@ # frozen_string_literal: true -json.partial! 'api_new/supporters/supporter', +json.partial! "api_new/supporters/supporter", supporter: event_entity diff --git a/app/views/api_new/supporters/show.json.jbuilder b/app/views/api_new/supporters/show.json.jbuilder index c72fd0f33..ce38427b8 100644 --- a/app/views/api_new/supporters/show.json.jbuilder +++ b/app/views/api_new/supporters/show.json.jbuilder @@ -3,4 +3,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! '/api_new/supporters/supporter', supporter: @supporter +json.partial! "/api_new/supporters/supporter", supporter: @supporter diff --git a/app/views/api_new/ticket_purchases/_ticket_purchase.json.jbuilder b/app/views/api_new/ticket_purchases/_ticket_purchase.json.jbuilder index 8a8aaa422..e2085f0a0 100644 --- a/app/views/api_new/ticket_purchases/_ticket_purchase.json.jbuilder +++ b/app/views/api_new/ticket_purchases/_ticket_purchase.json.jbuilder @@ -3,5 +3,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'ticket_purchase' - +json.object "ticket_purchase" diff --git a/app/views/api_new/ticket_purchases/object_events/_base.json.jbuilder b/app/views/api_new/ticket_purchases/object_events/_base.json.jbuilder index 4c5f983f1..697e64756 100644 --- a/app/views/api_new/ticket_purchases/object_events/_base.json.jbuilder +++ b/app/views/api_new/ticket_purchases/object_events/_base.json.jbuilder @@ -3,10 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! 'api_new/transaction_assignments/transaction_assignment', +json.partial! "api_new/transaction_assignments/transaction_assignment", transaction_assignment: event_entity.transaction_assignment, __expand: build_json_expansion_path_tree( - 'transaction', - 'transaction.transaction_assignments', - 'transaction.subtransaction.payments' - ) \ No newline at end of file + "transaction", + "transaction.transaction_assignments", + "transaction.subtransaction.payments" + ) diff --git a/app/views/api_new/transaction_assignments/_transaction_assignment.json.jbuilder b/app/views/api_new/transaction_assignments/_transaction_assignment.json.jbuilder index 5a53fc943..1db8657d1 100644 --- a/app/views/api_new/transaction_assignments/_transaction_assignment.json.jbuilder +++ b/app/views/api_new/transaction_assignments/_transaction_assignment.json.jbuilder @@ -2,15 +2,13 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.type 'trx_assignment' +json.type "trx_assignment" json.id transaction_assignment.to_houid -#json.created transaction_assignment.acreated.to_i +# json.created transaction_assignment.acreated.to_i handle_expansion(:supporter, transaction_assignment.supporter, {json: json, __expand: __expand}) -handle_expansion(:nonprofit, transaction_assignment.nonprofit, {json: json, __expand: __expand}) +handle_expansion(:nonprofit, transaction_assignment.nonprofit, {json: json, __expand: __expand}) handle_expansion(:transaction, transaction_assignment.trx, {json: json, __expand: __expand}) - json.partial! transaction_assignment.assignable, as: :assignable, __expand: __expand - diff --git a/app/views/api_new/transactions/_transaction.json.jbuilder b/app/views/api_new/transactions/_transaction.json.jbuilder index aa01fb678..610fe68fd 100644 --- a/app/views/api_new/transactions/_transaction.json.jbuilder +++ b/app/views/api_new/transactions/_transaction.json.jbuilder @@ -4,7 +4,7 @@ # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE json.id transaction.houid -json.object 'transaction' +json.object "transaction" handle_expansion(:supporter, transaction.supporter, {json: json, __expand: __expand}) @@ -13,7 +13,7 @@ handle_expansion(:nonprofit, transaction.nonprofit, {json: json, __expand: __exp json.created transaction.created.to_i json.amount do - json.partial! '/api_new/common/amount', amount: transaction.amount_as_money + json.partial! "/api_new/common/amount", amount: transaction.amount_as_money end handle_expansion(:subtransaction, transaction.subtransaction, {json: json, __expand: __expand}) @@ -26,4 +26,4 @@ handle_array_expansion(:payments, transaction.payments.ordered, {json: json, __e expansion.handle_item_expansion end -#json.url api_nonprofit_transaction_url(transaction.nonprofit, transaction) +# json.url api_nonprofit_transaction_url(transaction.nonprofit, transaction) diff --git a/app/views/api_new/transactions/index.json.jbuilder b/app/views/api_new/transactions/index.json.jbuilder index cb94db1d8..9ea3569c4 100644 --- a/app/views/api_new/transactions/index.json.jbuilder +++ b/app/views/api_new/transactions/index.json.jbuilder @@ -3,7 +3,7 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.data @transactions, partial: '/api_new/transactions/transaction', as: 'transaction', __expand: @__expand +json.data @transactions, partial: "/api_new/transactions/transaction", as: "transaction", __expand: @__expand json.current_page @transactions.current_page json.first_page @transactions.first_page? diff --git a/app/views/api_new/transactions/object_events/_base.json.jbuilder b/app/views/api_new/transactions/object_events/_base.json.jbuilder index ab96aa821..550321791 100644 --- a/app/views/api_new/transactions/object_events/_base.json.jbuilder +++ b/app/views/api_new/transactions/object_events/_base.json.jbuilder @@ -2,4 +2,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! event_entity, as: :transaction, __expand: build_json_expansion_path_tree(%w(subtransaction.payments transaction_assignments) ) +json.partial! event_entity, as: :transaction, __expand: build_json_expansion_path_tree(%w[subtransaction.payments transaction_assignments]) diff --git a/app/views/api_new/transactions/show.json.jbuilder b/app/views/api_new/transactions/show.json.jbuilder index 013a71858..0c0cbe28e 100644 --- a/app/views/api_new/transactions/show.json.jbuilder +++ b/app/views/api_new/transactions/show.json.jbuilder @@ -2,4 +2,4 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.partial! @transaction, as: :transaction, __expand: @__expand \ No newline at end of file +json.partial! @transaction, as: :transaction, __expand: @__expand diff --git a/app/views/api_new/users/_user.json.jbuilder b/app/views/api_new/users/_user.json.jbuilder index 27e4a31fd..d22e9386d 100644 --- a/app/views/api_new/users/_user.json.jbuilder +++ b/app/views/api_new/users/_user.json.jbuilder @@ -2,7 +2,7 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -json.object 'user' +json.object "user" json.roles user.nonprofit_admin_roles do |role| json.host role.host.to_houid diff --git a/app/views/campaigns/index.rabl b/app/views/campaigns/index.rabl index fe3366a87..0f4cfc951 100644 --- a/app/views/campaigns/index.rabl +++ b/app/views/campaigns/index.rabl @@ -2,7 +2,6 @@ object false child @campaigns => :data do - collection @campaigns, object_root: false - attributes :name, :total_raised, :goal_amount, :url, :id + collection @campaigns, object_root: false + attributes :name, :total_raised, :goal_amount, :url, :id end - diff --git a/app/views/custom_output/active_recurring_for_an_org.json.jbuilder b/app/views/custom_output/active_recurring_for_an_org.json.jbuilder index e09297f7a..256c1ff07 100644 --- a/app/views/custom_output/active_recurring_for_an_org.json.jbuilder +++ b/app/views/custom_output/active_recurring_for_an_org.json.jbuilder @@ -4,12 +4,12 @@ json.array! @supporter_group_by_email do |supporter_group| json.email supporter_group.email - all_supporters = supporter_group.supporters.map{|id| Supporter.includes(:recurring_donations, :tag_joins => :tag_master).find(id)} - json.tags all_supporters.map{|s| s.tag_joins.joins(:tag_master).where("NOT tag_masters.deleted").references(:tag_masters).pluck("tag_masters.name")}.flatten - recurrings = all_supporters.map{|supporter| supporter.recurring_donations.active.unfailed.order("start_date DESC")}.flatten.sort_by{|i| i.start_date}.reverse + all_supporters = supporter_group.supporters.map { |id| Supporter.includes(:recurring_donations, tag_joins: :tag_master).find(id) } + json.tags all_supporters.map { |s| s.tag_joins.joins(:tag_master).where("NOT tag_masters.deleted").references(:tag_masters).pluck("tag_masters.name") }.flatten + recurrings = all_supporters.map { |supporter| supporter.recurring_donations.active.unfailed.order("start_date DESC") }.flatten.sort_by { |i| i.start_date }.reverse json.active_recurring_donations recurrings do |recurring| json.supporter_id recurring.supporter.id json.amount recurring.amount json.start_date recurring.start_date.to_datetime.utc.to_i end -end \ No newline at end of file +end diff --git a/app/views/events/index.rabl b/app/views/events/index.rabl index f449fe4b8..09bd29386 100644 --- a/app/views/events/index.rabl +++ b/app/views/events/index.rabl @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later child @events => :data do - collection @events, object_root: false - attributes :name, :date, :url, :id + collection @events, object_root: false + attributes :name, :date, :url, :id end diff --git a/app/views/events/name_and_id.json.jbuilder b/app/views/events/name_and_id.json.jbuilder index f92d729b8..b777b208c 100644 --- a/app/views/events/name_and_id.json.jbuilder +++ b/app/views/events/name_and_id.json.jbuilder @@ -3,5 +3,5 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE json.array! @events do |event| - json.(event, :name, :id) -end \ No newline at end of file + json.call(event, :name, :id) +end diff --git a/app/views/mailchimp/list.json.jbuilder b/app/views/mailchimp/list.json.jbuilder index b9284aac3..a8c7b0557 100644 --- a/app/views/mailchimp/list.json.jbuilder +++ b/app/views/mailchimp/list.json.jbuilder @@ -1,13 +1,13 @@ -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later json.email_address @supporter.email -json.status 'subscribed' +json.status "subscribed" json.merge_fields do json.F_NAME @supporter.calculated_first_name json.L_NAME @supporter.calculated_last_name - @supporter.recurring_donations.active.order('start_date DESC').each_with_index do |item, i| - json.set! "RD_URL_#{i+1}", # we use i+1 because we want this to start at RD_URL_1 + @supporter.recurring_donations.active.order("start_date DESC").each_with_index do |item, i| + json.set! "RD_URL_#{i + 1}", # we use i+1 because we want this to start at RD_URL_1 edit_recurring_donation_url(id: item.id, t: item.edit_token, host: "us.commitchange.com") end -end \ No newline at end of file +end diff --git a/app/views/mailchimp/nonprofit_user_subscribe.json.jbuilder b/app/views/mailchimp/nonprofit_user_subscribe.json.jbuilder index a6bf3853e..853fbf181 100644 --- a/app/views/mailchimp/nonprofit_user_subscribe.json.jbuilder +++ b/app/views/mailchimp/nonprofit_user_subscribe.json.jbuilder @@ -1,10 +1,10 @@ -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later json.email_address @user.email -json.status 'subscribed' +json.status "subscribed" json.merge_fields do - json.NP_ID @nonprofit.id + json.NP_ID @nonprofit.id json.NP_SUPP @nonprofit.supporters.not_deleted.count json.FNAME @user.calculated_first_name || "" -end +end diff --git a/app/views/maps/all_npo_supporters.rabl b/app/views/maps/all_npo_supporters.rabl index cee568f34..b7c3f7803 100644 --- a/app/views/maps/all_npo_supporters.rabl +++ b/app/views/maps/all_npo_supporters.rabl @@ -2,6 +2,6 @@ object false child @map_data => :data do - collection @map_data, object_root: false - attributes :name, :latitude, :longitude, :id + collection @map_data, object_root: false + attributes :name, :latitude, :longitude, :id end diff --git a/app/views/maps/all_npos.rabl b/app/views/maps/all_npos.rabl index d511b8d02..51a52baa6 100644 --- a/app/views/maps/all_npos.rabl +++ b/app/views/maps/all_npos.rabl @@ -2,6 +2,6 @@ object false child @map_data => :data do - collection @map_data, object_root: false - attributes :name, :latitude, :longitude, :id, :email, :phone, :website + collection @map_data, object_root: false + attributes :name, :latitude, :longitude, :id, :email, :phone, :website end diff --git a/app/views/maps/all_supporters.rabl b/app/views/maps/all_supporters.rabl index 970c8663c..33877c75e 100644 --- a/app/views/maps/all_supporters.rabl +++ b/app/views/maps/all_supporters.rabl @@ -2,7 +2,6 @@ object false child @map_data => :data do - collection @map_data, object_root: false - attributes :name, :latitude, :longitude, :id, :email, :phone + collection @map_data, object_root: false + attributes :name, :latitude, :longitude, :id, :email, :phone end - diff --git a/app/views/maps/specific_npo_supporters.rabl b/app/views/maps/specific_npo_supporters.rabl index 25a945727..2dd8262b9 100644 --- a/app/views/maps/specific_npo_supporters.rabl +++ b/app/views/maps/specific_npo_supporters.rabl @@ -2,6 +2,6 @@ object false child @map_data => :data do - collection @map_data, object_root: false - attributes :name, :latitude, :longitude, :id, :email, :phone, :address, :city, :state_code, :total_raised + collection @map_data, object_root: false + attributes :name, :latitude, :longitude, :id, :email, :phone, :address, :city, :state_code, :total_raised end diff --git a/app/views/nonprofits/custom_field_joins/index.rabl b/app/views/nonprofits/custom_field_joins/index.rabl index cdae3879e..7cf899142 100644 --- a/app/views/nonprofits/custom_field_joins/index.rabl +++ b/app/views/nonprofits/custom_field_joins/index.rabl @@ -2,6 +2,6 @@ object false child @custom_field_joins => :data do - collection @custom_field_joins, object_root: false - attributes :name, :created_at, :id, :value + collection @custom_field_joins, object_root: false + attributes :name, :created_at, :id, :value end diff --git a/app/views/nonprofits/custom_field_masters/index.rabl b/app/views/nonprofits/custom_field_masters/index.rabl index d72b90f2c..4808fcce1 100644 --- a/app/views/nonprofits/custom_field_masters/index.rabl +++ b/app/views/nonprofits/custom_field_masters/index.rabl @@ -2,8 +2,6 @@ object false child @custom_field_masters => :data do - collection @custom_field_masters, object_root: false - attributes :name, :id, :created_at + collection @custom_field_masters, object_root: false + attributes :name, :id, :created_at end - - diff --git a/app/views/nonprofits/payments/show.rabl b/app/views/nonprofits/payments/show.rabl index af2ecb753..72a4d50c9 100644 --- a/app/views/nonprofits/payments/show.rabl +++ b/app/views/nonprofits/payments/show.rabl @@ -4,7 +4,7 @@ object @payment => :data attributes :gross_amount, :towards, :net_amount, :fee_total, :id, :date, :refund_total, :kind, :staff_comment node(:consider_donation_anonymous) do |p| - p.consider_anonymous? + p.consider_anonymous? end node(:fee_covered) do |p| @@ -17,116 +17,111 @@ end child :charge do attributes :created_at, :id - node(:status) {|c| c.status.humanize} + node(:status) { |c| c.status.humanize } end child :donation, object_root: false do - attributes :designation, :dedication, :origin_url, :id, :comment - + attributes :designation, :dedication, :origin_url, :id, :comment child :campaign, object_root: false do - attributes :name, :url, :id + attributes :name, :url, :id end - node(:campaign_gift){|d| {name: d.campaign_gifts.any? ? d.campaign_gifts.last.campaign_gift_option.name : nil}} + node(:campaign_gift) { |d| {name: d.campaign_gifts.any? ? d.campaign_gifts.last.campaign_gift_option.name : nil} } child :event, object_root: false do attributes :name, :url, :id end - child :recurring_donation, object_root: false do - attributes :interval, :time_unit, :created_at - end + child :recurring_donation, object_root: false do + attributes :interval, :time_unit, :created_at + end end child :disputes, object_root: false do attributes :id - node(:status) {|d| d.status&.humanize} - node(:reason) {|d| d.reason&.humanize} + node(:status) { |d| d.status&.humanize } + node(:reason) { |d| d.reason&.humanize } - node(:withdrawal_transaction) do |d| + node(:withdrawal_transaction) do |d| p = d&.withdrawal_transaction&.payment ret = p ? { - payment:{ - id: p.id, - net_amount: p.net_amount, + payment: { + id: p.id, + net_amount: p.net_amount, gross_amount: p.gross_amount, fee_total: p.fee_total, - href: nonprofits_payments_url(p.nonprofit, + href: nonprofits_payments_url(p.nonprofit, pid: p.id) - } - + } + } : nil - - ret + ret end - node(:reinstatement_transaction) do |d| + node(:reinstatement_transaction) do |d| p = d&.reinstatement_transaction&.payment ret = p ? { - payment:{ - id: p.id, - net_amount: p.net_amount, + payment: { + id: p.id, + net_amount: p.net_amount, gross_amount: p.gross_amount, fee_total: p.fee_total, - href: nonprofits_payments_url(p.nonprofit, + href: nonprofits_payments_url(p.nonprofit, pid: p.id) - } - + } + } : nil - - ret + ret end end -child :dispute_transaction, object_root:true do +child :dispute_transaction, object_root: true do attributes :id, :date - child :dispute do + child :dispute do attributes :id - node(:status) {|d| d.status.humanize} - node(:reason) {|d| d.reason.humanize} + node(:status) { |d| d.status.humanize } + node(:reason) { |d| d.reason.humanize } child :original_payment, object_root: false do attributes :id, :net_amount, :gross_amount, :fee_total - node(:href) {|p| nonprofits_payments_url(p.nonprofit, pid: p.id)} + node(:href) { |p| nonprofits_payments_url(p.nonprofit, pid: p.id) } end - end end child :refund do - attributes :reason, :comment, :disbursed + attributes :reason, :comment, :disbursed end child :offsite_payment do - attributes :check_number, :kind + attributes :check_number, :kind end - node(:ticket) do |payment| event = payment&.tickets&.last&.event h = { event: {name: event&.name, url: event&.url, id: event&.id}, - levels: payment.tickets.map{|t| "#{GetData.chain(t.ticket_level, :name)} (#{t.quantity}x)"}.join(", "), - discount: payment.tickets.map{|t| t.event_discount ? "#{t.event_discount.name} (#{t.event_discount.percent}%)" : nil}.compact.join(", ") + levels: payment.tickets.map { |t| "#{GetData.chain(t.ticket_level, :name)} (#{t.quantity}x)" }.join(", "), + discount: payment.tickets.map { |t| t.event_discount ? "#{t.event_discount.name} (#{t.event_discount.percent}%)" : nil }.compact.join(", ") } event ? h : nil end child :tickets, object_root: false do - attributes :id + attributes :id - child :ticket_level do - attributes :name - end + child :ticket_level do + attributes :name + end end child :supporter do - attributes :name, :email, :city, :state_code, :address, :zip_code, :phone, :id, :country - node(:url) {|s| nonprofits_supporters_url(s.nonprofit, {sid: s.id})} + attributes :name, :email, :city, :state_code, :address, :zip_code, :phone, :id, :country + node(:url) { |s| nonprofits_supporters_url(s.nonprofit, {sid: s.id}) } end child :nonprofit do - attributes :id + attributes :id end diff --git a/app/views/nonprofits/recurring_donations/show.rabl b/app/views/nonprofits/recurring_donations/show.rabl index edfc97034..6b747c796 100644 --- a/app/views/nonprofits/recurring_donations/show.rabl +++ b/app/views/nonprofits/recurring_donations/show.rabl @@ -3,17 +3,17 @@ object @recurring_donation => :data attributes :id, :total_given, :supporter_id, :interval, :time_unit, :designation, :anonymous, :start_date, :end_date, :created_at, :paydate, :edit_token child :donation do - attributes :amount, :designation + attributes :amount, :designation end child :supporter do - attributes :name, :email, :id, :anonymous + attributes :name, :email, :id, :anonymous end child :card do - attributes :name + attributes :name end node(:fee_covered) do |p| - !!p.misc_recurring_donation_info&.fee_covered + !!p.misc_recurring_donation_info&.fee_covered end diff --git a/app/views/nonprofits/refunds/index.rabl b/app/views/nonprofits/refunds/index.rabl index afe5ee757..5de93fbbe 100644 --- a/app/views/nonprofits/refunds/index.rabl +++ b/app/views/nonprofits/refunds/index.rabl @@ -2,7 +2,6 @@ object false child @refunds => :data do - collection @refunds, object_root: false - attributes :id, :amount, :created_at, :reason, :comment - + collection @refunds, object_root: false + attributes :id, :amount, :created_at, :reason, :comment end diff --git a/config/application.rb b/config/application.rb index d31bf4d47..216c26388 100755 --- a/config/application.rb +++ b/config/application.rb @@ -1,106 +1,105 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require_relative 'boot' -require 'rails/all' +require_relative "boot" +require "rails/all" # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module Commitchange - class Application < Rails::Application - # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.0 - - # Settings in config/environments/* take precedence over those specified here. - # Application configuration should go into files in config/initializers - # -- all .rb files in that directory are automatically loaded. - - # Custom directories with classes and modules you want to be autoloadable. - # config.autoload_paths += %W(#{config.root}/extras) - #config.autoload_paths += config.root + File.join('app', 'legacy_lib') - #config.eager_load_paths += Dir["#{config.root}/lib/**/"] - - # config.paths.add File.join('lib'), glob: File.join('**') - - # Only load the plugins named here, in the order given (default is alphabetical). - # :all can be used as a placeholder for all plugins not explicitly named. - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Activate observers that should always be running. - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. - # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. - config.time_zone = 'UTC' - - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - # config.i18n.default_locale = :de - - # Configure the default encoding used in templates for Ruby 1.9. - config.encoding = "utf-8" - - # Enable escaping HTML in JSON. - config.active_support.escape_html_entities_in_json = true - - # Use SQL instead of Active Record's schema dumper when creating the database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - #config.active_record.schema_format = :sql - - # Enable the asset pipeline - config.assets.enabled = true - - # Precompile all "page" files - config.assets.precompile << Proc.new do |path| - if path =~ /.*page\.(css|js)/ - puts "Compiling asset: " + path - true - else - false - end - end - - # Version of your assets, change this If you want to expire all your assets - # config.assets.version = '1.0' - - # For Rails 3.1 on Heroku: - # Forces the application to not access the DB - # or load models when precompiling your assets. - # from: devise gem installation instructions/suggestions - # config.assets.initialize_on_precompile = true - - config.i18n.enforce_available_locales = false - - # Add trailing slashes to all routes - # config.action_controller.default_url_options = {:trailing_slash => true} - # - #config.browserify_rails.commandline_options = "-t [ babelify --presets es2015 ]" - - # Require `belongs_to` associations by default. Previous versions had false. - # it's a bunch of work to verify everything that should be marked optional actually is. - # we should do that over time. - # Added in rails 5.0 - config.active_record.belongs_to_required_by_default = false - - # just have unknown assets return path like they did before Rails 5.1 - Rails.application.config.assets.unknown_asset_fallback = true - - # keep our forgery protection in ApplicationController, not ActionController::BaseController - # added in Rails 5.2 - config.action_controller.default_protect_from_forgery = false - - config.middleware.insert_before 0, Rack::Cors do - allow do - origins '*' - resource '*', - headers: :any, - methods: [:get, :post, :put, :patch, :delete, :options, :head] - end - end - - config.active_job.queue_adapter = :delayed_job - - end + class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 7.0 + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + # config.autoload_paths += config.root + File.join('app', 'legacy_lib') + # config.eager_load_paths += Dir["#{config.root}/lib/**/"] + + # config.paths.add File.join('lib'), glob: File.join('**') + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + config.time_zone = "UTC" + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Enable escaping HTML in JSON. + config.active_support.escape_html_entities_in_json = true + + # Use SQL instead of Active Record's schema dumper when creating the database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Enable the asset pipeline + config.assets.enabled = true + + # Precompile all "page" files + config.assets.precompile << proc do |path| + if /.*page\.(css|js)/.match?(path) + puts "Compiling asset: " + path + true + else + false + end + end + + # Version of your assets, change this If you want to expire all your assets + # config.assets.version = '1.0' + + # For Rails 3.1 on Heroku: + # Forces the application to not access the DB + # or load models when precompiling your assets. + # from: devise gem installation instructions/suggestions + # config.assets.initialize_on_precompile = true + + config.i18n.enforce_available_locales = false + + # Add trailing slashes to all routes + # config.action_controller.default_url_options = {:trailing_slash => true} + # + # config.browserify_rails.commandline_options = "-t [ babelify --presets es2015 ]" + + # Require `belongs_to` associations by default. Previous versions had false. + # it's a bunch of work to verify everything that should be marked optional actually is. + # we should do that over time. + # Added in rails 5.0 + config.active_record.belongs_to_required_by_default = false + + # just have unknown assets return path like they did before Rails 5.1 + Rails.application.config.assets.unknown_asset_fallback = true + + # keep our forgery protection in ApplicationController, not ActionController::BaseController + # added in Rails 5.2 + config.action_controller.default_protect_from_forgery = false + + config.middleware.insert_before 0, Rack::Cors do + allow do + origins "*" + resource "*", + headers: :any, + methods: [:get, :post, :put, :patch, :delete, :options, :head] + end + end + + config.active_job.queue_adapter = :delayed_job + end end diff --git a/config/boot.rb b/config/boot.rb index 3a9aadeb3..651aa085c 100755 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,8 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rubygems' +require "rubygems" # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) -require 'bootsnap/setup' +require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) +require "bootsnap/setup" diff --git a/config/environment.rb b/config/environment.rb index dbde554f0..b0a3517db 100755 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # Load the Rails application. -require_relative 'application' +require_relative "application" Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::UTF_8 -@ignore_dotenv = ENV['IGNORE_DOTENV'] -@env = Rails.env || 'development' -unless (@ignore_dotenv) - require 'dotenv' - if @env == 'test' +@ignore_dotenv = ENV["IGNORE_DOTENV"] +@env = Rails.env || "development" +unless @ignore_dotenv + require "dotenv" + if @env == "test" if File.file?(".env.#{@env}") Dotenv.load ".env.#{@env}" end @@ -17,20 +17,18 @@ end end -@org_name = ENV['ORG_NAME'] || 'default_organization' -puts "config files .env .env.#{@env} ./config/settings.#{@env}.yml#{ @env != 'test' ? " ./config/#{@org_name}.yml": " "} #{ @env != 'test' ? " ./config/#{@org_name}.#{@env}.yml": " "} #{ @env == 'test' ? "./config/settings.test.yml" : ""}" -if Rails.env == 'test' +@org_name = ENV["ORG_NAME"] || "default_organization" +puts "config files .env .env.#{@env} ./config/settings.#{@env}.yml#{(@env != "test") ? " ./config/#{@org_name}.yml" : " "} #{(@env != "test") ? " ./config/#{@org_name}.#{@env}.yml" : " "} #{(@env == "test") ? "./config/settings.test.yml" : ""}" +if Rails.env.test? Settings.add_source!("./config/settings.test.yml") else Settings.add_source!("./config/#{@org_name}.yml") Settings.add_source!("./config/#{@org_name}.#{Rails.env}.yml") end +# Settings.add_source!("./config/#{@org_name}.#{Rails.env}.yml") - -#Settings.add_source!("./config/#{@org_name}.#{Rails.env}.yml") - -#we load the schema now because we didn't want to do so until we loaded EVERYTHING +# we load the schema now because we didn't want to do so until we loaded EVERYTHING Config.setup do |config| config.schema do required(:general).schema do @@ -45,21 +43,19 @@ # the relative path from asset_host root to your poweredby email logo (PNG, 150px wide) required(:poweredby_logo).filled(:str?) - end required(:default).schema do required(:image).schema do - #the path on your image.host to your default profile image + # the path on your image.host to your default profile image required(:profile).filled(:str?) - #the path on your image.host to your default nonprofit image + # the path on your image.host to your default nonprofit image required(:nonprofit).filled(:str?) - #the path on your image.host to your default campaign background image + # the path on your image.host to your default campaign background image required(:campaign).filled(:str?) end - end required(:aws).schema do @@ -77,7 +73,7 @@ end required(:mailer).schema do - #an action mailer delivery method + # an action mailer delivery method # Default is sendmail required(:delivery_method).filled(:str?) @@ -129,10 +125,10 @@ optional(:maps).schema do # the map provider to use. Currently that's just Google Maps or nothing # Default is nil - optional(:provider).value(included_in?:['google', nil]) + optional(:provider).value(included_in?: ["google", nil]) optional(:options).schema do - #key for your google maps instance + # key for your google maps instance optional(:key).filled(:str?) end end @@ -141,10 +137,9 @@ # The editor used for editing nonprofit, campaign # and event pages and some email templates # Default is 'quill' - required(:editor).value(included_in?:['quill', 'froala']) + required(:editor).value(included_in?: ["quill", "froala"]) optional(:editor_options).schema do - # Froala Key if your use froala # Default is nil (you need to get a key) required(:froala_key).filled(:str?) @@ -160,7 +155,7 @@ # Default is 1200 (20 minutes) required(:expiration_time).filled(:int?) - #event donation source tokens are unique. + # event donation source tokens are unique. # The idea is someone may want to donate multiple times at an event without # staff needing to enter their info again. Additionally, they # may want to do it after the event without staff @@ -173,14 +168,13 @@ # The time (in seconds) after an event ends that this token can be used. # Default is 1728000 (20 days) required(:time_after_event).filled(:int?) - end end - #sets the default language for the UI + # sets the default language for the UI required(:language).filled(:str?) - #sets the list of locales available + # sets the list of locales available required(:available_locales).each(:str?) # your default language needs to be in the available locales @@ -193,7 +187,6 @@ # Whether to show state fields in the donation wizard optional(:show_state_fields).filled(:bool?) - required(:intntl).schema do # the supporter currencies for the site as abbreviations required(:currencies).each(:str?) @@ -202,17 +195,16 @@ required(:all_currencies).each do # each currency must have the following - # the unit. For 'usd', this would be "dollars" - required(:unit).filled(:str?) - # the abbreviation of the currency. For 'usd', this would be "usd" - required(:abbv).filled(:str?) - # the subunit of the currency. For 'usd', this would be "cents" - required(:subunit).filled(:str?) - # the currency symbol of the currency. For 'usd', this would be "$" - required(:symbol).filled(:str?) - - required(:format).filled(:str?) + # the unit. For 'usd', this would be "dollars" + required(:unit).filled(:str?) + # the abbreviation of the currency. For 'usd', this would be "usd" + required(:abbv).filled(:str?) + # the subunit of the currency. For 'usd', this would be "cents" + required(:subunit).filled(:str?) + # the currency symbol of the currency. For 'usd', this would be "$" + required(:symbol).filled(:str?) + required(:format).filled(:str?) end # an array of country codes to override the default set of countries @@ -225,8 +217,6 @@ # Xavier, I need you document this :) optional(:integration) - - end required(:default_bp).schema do @@ -254,7 +244,7 @@ # complete, corresponding source optional(:ccs).schema do - optional(:ccs_method).value(included_in?: %w(local_tar_gz github)) + optional(:ccs_method).value(included_in?: %w[local_tar_gz github]) # only used for github # NOTE: for github you need to have the hash of the corresponding source in $RAILS_ROOT/CCS_HASH @@ -277,10 +267,9 @@ # the url, absolute or relative, that visitors should be redirected to optional(:maintenance_page).filled(:str?) - end - #the url for your button. As a default, it takes what's in CDN.url + # the url for your button. As a default, it takes what's in CDN.url optional(:button_domain).schema do required(:url).filled?(:str) end diff --git a/config/environments/ci.rb b/config/environments/ci.rb index c808c1d56..ce81a0972 100755 --- a/config/environments/ci.rb +++ b/config/environments/ci.rb @@ -19,11 +19,11 @@ # config.action_mailer.delivery_method = :aws_ses # config.action_mailer.default_url_options = { host: 'commitchange.com' } config.action_mailer.delivery_method = Settings.mailer.delivery_method.to_sym - config.action_mailer.smtp_settings = { address: Settings.mailer.address, port: Settings.mailer.port } - config.action_mailer.smtp_settings['user_name']= Settings.mailer.username if Settings.mailer.username - config.action_mailer.smtp_settings['password']= Settings.mailer.password if Settings.mailer.password + config.action_mailer.smtp_settings = {address: Settings.mailer.address, port: Settings.mailer.port} + config.action_mailer.smtp_settings["user_name"] = Settings.mailer.username if Settings.mailer.username + config.action_mailer.smtp_settings["password"] = Settings.mailer.password if Settings.mailer.password - config.action_mailer.default_url_options = { host: Settings.mailer.host } + config.action_mailer.default_url_options = {host: Settings.mailer.host} # Print deprecation notices to the Rails logger config.active_support.deprecation = :log @@ -49,4 +49,4 @@ ActiveRecord::Base.logger = nil end NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY = 5.minutes -end \ No newline at end of file +end diff --git a/config/environments/development.rb b/config/environments/development.rb index 1cdb5a1a0..fb3476aa2 100755 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -12,8 +12,8 @@ # Do not eager load code on boot. config.eager_load = false - # Log error messages when you accidentally call methods on nil. - config.whiny_nils = true + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true # Show full error reports. config.consider_all_requests_local = true @@ -23,13 +23,13 @@ # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join('tmp', 'caching-dev.txt').exist? + if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{2.days.to_i}" + "Cache-Control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false @@ -40,22 +40,22 @@ # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local - config.action_mailer.delivery_method = :letter_opener - config.action_mailer.perform_deliveries = true + config.action_mailer.delivery_method = :letter_opener + config.action_mailer.perform_deliveries = true - config.action_mailer.default_url_options = { host: 'localhost', port: 5000} - config.action_mailer.smtp_settings = { address: Settings.mailer.address, port: Settings.mailer.port } - config.action_mailer.smtp_settings['user_name']= Settings.mailer.username if Settings.mailer.username - config.action_mailer.smtp_settings['password']= Settings.mailer.password if Settings.mailer.password + config.action_mailer.default_url_options = {host: "localhost", port: 5000} + config.action_mailer.smtp_settings = {address: Settings.mailer.address, port: Settings.mailer.port} + config.action_mailer.smtp_settings["user_name"] = Settings.mailer.username if Settings.mailer.username + config.action_mailer.smtp_settings["password"] = Settings.mailer.password if Settings.mailer.password - # creds = Aws::Credentials.new(ENV['AWS_ACCESS_KEY'], ENV['AWS_SECRET_ACCESS_KEY']) + # creds = Aws::Credentials.new(ENV['AWS_ACCESS_KEY'], ENV['AWS_SECRET_ACCESS_KEY']) - # Aws::Rails.add_action_mailer_delivery_method( - # :ses, - # credentials: creds, - # region: 'us-east-1' - # ) - # config.action_mailer.delivery_method = :ses + # Aws::Rails.add_action_mailer_delivery_method( + # :ses, + # credentials: creds, + # region: 'us-east-1' + # ) + # config.action_mailer.delivery_method = :ses # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false @@ -76,12 +76,12 @@ # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - + # Raise exception on mass assignment protection for Active Record models - config.active_record.mass_assignment_sanitizer = :strict + config.active_record.mass_assignment_sanitizer = :strict - # Do not compress assets - config.assets.compress = false + # Do not compress assets + config.assets.compress = false # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large @@ -105,17 +105,16 @@ config.file_watcher = ActiveSupport::EventedFileUpdateChecker config.dependency_loading = true if $rails_rake_task - # Turn this on if you want to mess with code inside /node_modules - # config.browserify_rails.evaluate_node_modules = true + # Turn this on if you want to mess with code inside /node_modules + # config.browserify_rails.evaluate_node_modules = true - config.middleware.use I18n::JS::Middleware + config.middleware.use I18n::JS::Middleware config.middleware.use Rack::Attack NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY = 5.minutes - ActiveSupport::Notifications.subscribe("factory_bot.run_factory") do |name, start, finish, id, payload| - Rails.logger.debug(payload) - - end + ActiveSupport::Notifications.subscribe("factory_bot.run_factory") do |name, start, finish, id, payload| + Rails.logger.debug(payload) + end end diff --git a/config/environments/production.rb b/config/environments/production.rb index ac15a069f..18983703e 100755 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -13,19 +13,18 @@ # Rake tasks automatically ignore this option for performance. config.eager_load = true - config.cache_store = :mem_cache_store, - (ENV["MEMCACHIER_SERVERS"] || "").split(","), - {:username => ENV["MEMCACHIER_USERNAME"], - :password => ENV["MEMCACHIER_PASSWORD"], - :failover => true, - :socket_timeout => 1.5, - :socket_failure_delay => 0.2, - :down_retry_delay => 60, - :expires_in => 5.hours, :compress => true, pool_size: 10 - } + config.cache_store = :mem_cache_store, + (ENV["MEMCACHIER_SERVERS"] || "").split(","), + {username: ENV["MEMCACHIER_USERNAME"], + password: ENV["MEMCACHIER_PASSWORD"], + failover: true, + socket_timeout: 1.5, + socket_failure_delay: 0.2, + down_retry_delay: 60, + expires_in: 5.hours, compress: true, pool_size: 10} # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false + config.consider_all_requests_local = false config.action_controller.perform_caching = true # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] @@ -48,9 +47,9 @@ # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = 'http://assets.example.com' - # Specifies the header that your server uses for sending files - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # Specifies the header that your server uses for sending files + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for nginx # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local @@ -68,7 +67,7 @@ config.log_level = :debug # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -77,37 +76,37 @@ # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "commitchange_production" - # Enable serving of images, stylesheets, and JavaScripts from an asset server - - cdn_url= URI(Settings.cdn.url) - cdn_url = cdn_url.to_s - config.action_controller.asset_host = cdn_url - config.action_mailer.asset_host = cdn_url - - # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - creds = Aws::Credentials.new(ENV['AWS_ACCESS_KEY'], ENV['AWS_SECRET_ACCESS_KEY']) - - Aws::Rails.add_action_mailer_delivery_method( - :ses, - credentials: creds, - region: 'us-east-1' - ) - - config.action_mailer.perform_caching = false - - # Disable delivery errors, bad email addresses will be ignored - # config.action_mailer.raise_delivery_errors = false - config.action_mailer.delivery_method = :ses - config.action_mailer.default_url_options = { host: Settings.mailer.host } - # Precompile all "page" files, it needs to be set here so the proper env is setup - config.assets.precompile << Proc.new do |path| - if path =~ /.*page\.(css|js)/ - puts "Compiling asset: " + path - true - else - false - end - end + # Enable serving of images, stylesheets, and JavaScripts from an asset server + + cdn_url = URI(Settings.cdn.url) + cdn_url = cdn_url.to_s + config.action_controller.asset_host = cdn_url + config.action_mailer.asset_host = cdn_url + + # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) + creds = Aws::Credentials.new(ENV["AWS_ACCESS_KEY"], ENV["AWS_SECRET_ACCESS_KEY"]) + + Aws::Rails.add_action_mailer_delivery_method( + :ses, + credentials: creds, + region: "us-east-1" + ) + + config.action_mailer.perform_caching = false + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + config.action_mailer.delivery_method = :ses + config.action_mailer.default_url_options = {host: Settings.mailer.host} + # Precompile all "page" files, it needs to be set here so the proper env is setup + config.assets.precompile << proc do |path| + if /.*page\.(css|js)/.match?(path) + puts "Compiling asset: " + path + true + else + false + end + end # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). @@ -133,9 +132,9 @@ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) + logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) + config.logger = ActiveSupport::TaggedLogging.new(logger) end # Do not dump schema after migrations. @@ -143,7 +142,7 @@ config.dependency_loading = true if $rails_rake_task - NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY = 2.hours + NONPROFIT_VERIFICATION_SEND_EMAIL_DELAY = 2.hours # Inserts middleware to perform automatic connection switching. # The `database_selector` hash is used to pass options to the DatabaseSelector diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 9d081539a..e6253a890 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -1,11 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require_relative './production' +require_relative "production" Rails.application.configure do - # Settings specified here will take precedence over those in config/application.rb and config/environments/production.rb + # Settings specified here will take precedence over those in config/application.rb and config/environments/production.rb - config.action_mailer.delivery_method = Settings.mailer.delivery_method.to_sym - config.action_mailer.default_url_options = { host: 'commitchange-test.herokuapp.com' } - # we want to be able to show mailer previews - config.action_mailer.show_previews = true + config.action_mailer.delivery_method = Settings.mailer.delivery_method.to_sym + config.action_mailer.default_url_options = {host: "commitchange-test.herokuapp.com"} + # we want to be able to show mailer previews + config.action_mailer.show_previews = true end diff --git a/config/environments/test.rb b/config/environments/test.rb index 09f299ad2..bb282bec6 100755 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -25,7 +25,7 @@ } # Show full error reports and disable caching. - config.consider_all_requests_local = true + config.consider_all_requests_local = true config.action_controller.perform_caching = false config.cache_store = :null_store @@ -45,7 +45,7 @@ # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test config.action_mailer.raise_delivery_errors = false - config.action_mailer.default_url_options = { host: 'localhost:8080' } + config.action_mailer.default_url_options = {host: "localhost:8080"} # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr @@ -76,9 +76,8 @@ config.action_controller.allow_forgery_protection = false config.cache_store = :memory_store - - ENV['THROTTLE_SUPPORTER_LIMIT'] = '10' - ENV['THROTTLE_SUPPORTER_PERIOD'] = '60' + ENV["THROTTLE_SUPPORTER_LIMIT"] = "10" + ENV["THROTTLE_SUPPORTER_PERIOD"] = "60" config.after_initialize do # ActiveRecord::Base.logger = nil diff --git a/config/initializers/1_strict_loading_monkeypatch.rb b/config/initializers/1_strict_loading_monkeypatch.rb index ff3d7f6ec..b2a76f87b 100644 --- a/config/initializers/1_strict_loading_monkeypatch.rb +++ b/config/initializers/1_strict_loading_monkeypatch.rb @@ -8,4 +8,4 @@ def strict_loading_mode end end -ActiveSupport.on_load(:active_record) { prepend ActiveRecordBaseMonkeyPatch } \ No newline at end of file +ActiveSupport.on_load(:active_record) { prepend ActiveRecordBaseMonkeyPatch } diff --git a/config/initializers/airbrake.rb b/config/initializers/airbrake.rb index 878e1ab9c..cb9cbd9c5 100644 --- a/config/initializers/airbrake.rb +++ b/config/initializers/airbrake.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'airbrake/delayed_job' +require "airbrake/delayed_job" # Airbrake is an online tool that provides robust exception tracking in your Rails # applications. In doing so, it allows you to easily review errors, tie an error @@ -10,14 +10,14 @@ # # Configuration details: # https://github.com/airbrake/airbrake-ruby#configuration -if ENV['AIRBRAKE_PROJECT_ID'] && ENV['AIRBRAKE_API_KEY'] +if ENV["AIRBRAKE_PROJECT_ID"] && ENV["AIRBRAKE_API_KEY"] Airbrake.configure do |c| # You must set both project_id & project_key. To find your project_id and # project_key navigate to your project's General Settings and copy the values # from the right sidebar. # https://github.com/airbrake/airbrake-ruby#project_id--project_key - c.project_id = ENV['AIRBRAKE_PROJECT_ID'] || 1 - c.project_key = ENV['AIRBRAKE_API_KEY'] || 1 + c.project_id = ENV["AIRBRAKE_PROJECT_ID"] || 1 + c.project_key = ENV["AIRBRAKE_API_KEY"] || 1 # Configures the root directory of your project. Expects a String or a # Pathname, which represents the path to your project. Providing this option @@ -43,7 +43,7 @@ # unwanted environments such as :test. # NOTE: This option *does not* work if you don't set the 'environment' option. # https://github.com/airbrake/airbrake-ruby#ignore_environments - c.ignore_environments = %w(test development staging) + c.ignore_environments = %w[test development staging] # A list of parameters that should be filtered out of what is sent to # Airbrake. By default, all "password" attributes will have their contents @@ -51,7 +51,7 @@ # https://github.com/airbrake/airbrake-ruby#blacklist_keys c.blocklist_keys = [/password/i, /authorization/i] - c.performance_stats = !!ENV['CHECK_PERFORMANCE'] + c.performance_stats = !!ENV["CHECK_PERFORMANCE"] end # A filter that collects request body information. Enable it if you are sure you @@ -59,21 +59,18 @@ # https://github.com/airbrake/airbrake#requestbodyfilter # Airbrake.add_filter(Airbrake::Rack::RequestBodyFilter.new) - - - # config.ignore << "ArgumentError: invalid byte sequence in UTF-8" # config.ignore << "SIGTERM" # end ignore_exceptions = [ActionDispatch::RemoteIp::IpSpoofAttackError, Encoding::CompatibilityError, - EOFError, [SignalException, lambda {|e| e.signo == Signal.list['TERM']}]] + EOFError, [SignalException, lambda { |e| e.signo == Signal.list["TERM"] }]] Airbrake.add_filter do |notice| ignore_exceptions.each do |type| if type.class == Array notice.ignore! if notice.stash[:exception].is_a?(type[0]) && type[1].call(notice.stash[:exception]) - else - notice.ignore! if notice.stash[:exception].is_a?(type) + elsif notice.stash[:exception].is_a?(type) + notice.ignore! end end end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 993e063ad..ead199cc9 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -1,7 +1,7 @@ # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = '1.0' +Rails.application.config.assets.version = "1.0" # Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path diff --git a/config/initializers/aws.rb b/config/initializers/aws.rb index 8872e5aa6..46ccb49c0 100644 --- a/config/initializers/aws.rb +++ b/config/initializers/aws.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later Aws.config.update({ - region: Settings.aws.region || 'us-west-1', # I'm hardcoding this because it's our damn code. + region: Settings.aws.region || "us-west-1", # I'm hardcoding this because it's our damn code. credentials: Aws::Credentials.new(Settings.aws.access_key_id, Settings.aws.secret_access_key) }) diff --git a/config/initializers/block_ips.rb b/config/initializers/block_ips.rb index ed9f52f0c..a0e1ce44c 100644 --- a/config/initializers/block_ips.rb +++ b/config/initializers/block_ips.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -Rack::Attack.blocklist('block charge abusers') do |req| - ['54.159.242.229', - '54.161.246.233', - '54.211.94.199' - ].include? req.ip +Rack::Attack.blocklist("block charge abusers") do |req| + ["54.159.242.229", + "54.161.246.233", + "54.211.94.199"].include? req.ip end diff --git a/config/initializers/blocked_supporters.rb b/config/initializers/blocked_supporters.rb index 0ecb88cda..62b46cf70 100644 --- a/config/initializers/blocked_supporters.rb +++ b/config/initializers/blocked_supporters.rb @@ -1 +1 @@ -BLOCKED_SUPPORTERS = ['nasujo@larjem.com'] \ No newline at end of file +BLOCKED_SUPPORTERS = ["nasujo@larjem.com"] diff --git a/config/initializers/blocking.rb b/config/initializers/blocking.rb index cece44d28..adb9c9b1c 100644 --- a/config/initializers/blocking.rb +++ b/config/initializers/blocking.rb @@ -7,5 +7,4 @@ request.delete? || request.options? || request.put?) - -end \ No newline at end of file +end diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb index be2cb6b28..b38125d15 100755 --- a/config/initializers/carrierwave.rb +++ b/config/initializers/carrierwave.rb @@ -12,13 +12,13 @@ end else CarrierWave.configure do |config| - config.storage = :aws + config.storage = :aws config.aws_bucket = Settings.aws.bucket - config.aws_acl = :public_read + config.aws_acl = :public_read config.asset_host = Settings.image&.host || "https://#{Settings.aws.bucket}.s3.amazonaws.com" config.aws_authenticated_url_expiration = 60 * 60 * 24 * 365 config.aws_credentials = { - access_key_id: Settings.aws.access_key_id, + access_key_id: Settings.aws.access_key_id, secret_access_key: Settings.aws.secret_access_key, region: Settings.aws.region } diff --git a/config/initializers/chunked_uploader.rb b/config/initializers/chunked_uploader.rb index 37610642b..0db40cf28 100644 --- a/config/initializers/chunked_uploader.rb +++ b/config/initializers/chunked_uploader.rb @@ -1,4 +1,4 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later Rails.application.config.after_initialize do - CHUNKED_UPLOADER = ENV['CHUNKED_UPLOAD_CLASS'] ? ENV['CHUNKED_UPLOAD_CLASS'].constantize : ChunkedUploader::S3 + CHUNKED_UPLOADER = ENV["CHUNKED_UPLOAD_CLASS"] ? ENV["CHUNKED_UPLOAD_CLASS"].constantize : ChunkedUploader::S3 end diff --git a/config/initializers/config.rb b/config/initializers/config.rb index b253585e0..eb3cf352b 100644 --- a/config/initializers/config.rb +++ b/config/initializers/config.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later Config.setup do |config| # Name of the constant exposing loaded settings - config.const_name = 'Settings' + config.const_name = "Settings" config.use_env = true # Ability to remove elements of the array set in earlier loaded settings file. For example value: '--'. # diff --git a/config/initializers/core_exts.rb b/config/initializers/core_exts.rb index 8d5cf9fd1..9942c8643 100644 --- a/config/initializers/core_exts.rb +++ b/config/initializers/core_exts.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|l| require l } +Dir[Rails.root.join("lib/core_ext/*.rb").to_s].each { |l| require l } diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index c944a84c9..86abb1fd6 100755 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -2,232 +2,230 @@ # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| - # ==> Mailer Configuration - # Configure the e-mail address which will be shown in Devise::Mailer, - # note that it will be overwritten if you use your own mailer class with default "from" parameter. - config.mailer_sender = Settings.devise.mailer_sender - - # Configure the class responsible to send e-mails. - # config.mailer = "Devise::Mailer" - - # ==> ORM configuration - # Load and configure the ORM. Supports :active_record (default) and - # :mongoid (bson_ext recommended) by default. Other ORMs may be - # available as additional gems. - require 'devise/orm/active_record' - - # ==> Configuration for any authentication mechanism - # Configure which keys are used when authenticating a user. The default is - # just :email. You can configure it to use [:username, :subdomain], so for - # authenticating a user, both parameters are required. Remember that those - # parameters are used only when authenticating and not when retrieving from - # session. If you need permissions, you should implement that in a before filter. - # You can also supply a hash where the value is a boolean determining whether - # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [ :email ] - - # Configure parameters from the request object used for authentication. Each entry - # given should be a request method and it will automatically be passed to the - # find_for_authentication method and considered in your model lookup. For instance, - # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. - # The same considerations mentioned for authentication_keys also apply to request_keys. - # config.request_keys = [] - - # Configure which authentication keys should be case-insensitive. - # These keys will be downcased upon creating or modifying a user and when used - # to authenticate or find a user. Default is :email. - config.case_insensitive_keys = [ :email ] - - # Configure which authentication keys should have whitespace stripped. - # These keys will have whitespace before and after removed upon creating or - # modifying a user and when used to authenticate or find a user. Default is :email. - config.strip_whitespace_keys = [ :email ] - - # Tell if authentication through request.params is enabled. True by default. - # It can be set to an array that will enable params authentication only for the - # given strategies, for example, `config.params_authenticatable = [:database]` will - # enable it only for database (email + password) authentication. - # config.params_authenticatable = true - - # Tell if authentication through HTTP Basic Auth is enabled. False by default. - # It can be set to an array that will enable http authentication only for the - # given strategies, for example, `config.http_authenticatable = [:token]` will - # enable it only for token authentication. - config.http_authenticatable = true - - # If http headers should be returned for AJAX requests. True by default. - # config.http_authenticatable_on_xhr = true - - # The realm used in Http Basic Authentication. "Application" by default. - # config.http_authentication_realm = "Application" - - # It will change confirmation, password recovery and other workflows - # to behave the same regardless if the e-mail provided was right or wrong. - # Does not affect registerable. - # config.paranoid = true - - # By default Devise will store the user in session. You can skip storage for - # :http_auth and :token_auth by adding those symbols to the array below. - # Notice that if you are skipping storage for all authentication paths, you - # may want to disable generating routes to Devise's sessions controller by - # passing :skip => :sessions to `devise_for` in your config/routes.rb - config.skip_session_storage = [:http_auth] - - # ==> Configuration for :database_authenticatable - # For bcrypt, this is the cost for hashing the password and defaults to 10. If - # using other encryptors, it sets how many times you want the password re-encrypted. - # - # Limiting the stretches to just one in testing will increase the performance of - # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use - # a value less than 10 in other environments. - config.stretches = Rails.env.test? ? 1 : 10 - - - # ==> Configuration for :confirmable - # A period that the user is allowed to access the website even without - # confirming his account. For instance, if set to 2.days, the user will be - # able to access the website for two days without confirming his account, - # access will be blocked just in the third day. Default is 0.days, meaning - # the user cannot access the website without confirming his account. - # config.allow_unconfirmed_access_for = 2.days - - # If true, requires any email changes to be confirmed (exactly the same way as - # initial account confirmation) to be applied. Requires additional unconfirmed_email - # db field (see migrations). Until confirmed new email is stored in - # unconfirmed email column, and copied to email column on successful confirmation. - config.reconfirmable = true - - # Defines which key will be used when confirming an account - # config.confirmation_keys = [ :email ] - - # ==> Configuration for :rememberable - # The time the user will be remembered without asking for credentials again. - # config.remember_for = 2.weeks - - # If true, extends the user's remember period when remembered via cookie. - # config.extend_remember_period = false - - # Options to be passed to the created cookie. For instance, you can set - # :secure => true in order to force SSL only cookies. - # config.rememberable_options = {} - - # ==> Configuration for :validatable - # Range for password length. Default is 6..128. - # config.password_length = 6..128 - - # Email regex used to validate email formats. It simply asserts that - # an one (and only one) @ exists in the given string. This is mainly - # to give user feedback and not to assert the e-mail validity. - # config.email_regexp = /\A[^@]+@[^@]+\z/ - - # ==> Configuration for :timeoutable - # The time you want to timeout the user session without activity. After this - # time the user will be asked for credentials again. Default is 30 minutes. - # config.timeout_in = 30.minutes - - # If true, expires auth token on session timeout. - # config.expire_auth_token_on_timeout = false - - # ==> Configuration for :lockable - # Defines which strategy will be used to lock an account. - # :failed_attempts = Locks an account after a number of failed attempts to sign in. - # :none = No lock strategy. You should handle locking by yourself. - config.lock_strategy = :failed_attempts - - # Defines which key will be used when locking and unlocking an account - # config.unlock_keys = [ :email ] - - # Defines which strategy will be used to unlock an account. - # :email = Sends an unlock link to the user email - # :time = Re-enables login after a certain amount of time (see :unlock_in below) - # :both = Enables both strategies - # :none = No unlock strategy. You should handle unlocking by yourself. - config.unlock_strategy = :email - - # Number of authentication tries before locking an account if lock_strategy - # is failed attempts. - config.maximum_attempts = 10 - - # Time interval to unlock the account if :time is enabled as unlock_strategy. - # config.unlock_in = 1.hour - - # ==> Configuration for :recoverable - # - # Defines which key will be used when recovering the password for an account - # config.reset_password_keys = [ :email ] - - # Time interval you can reset your password with a reset password key. - # Don't put a too small interval or your users won't have the time to - # change their passwords. - config.reset_password_within = 6.hours - - # ==> Configuration for :encryptable - # Allow you to use another encryption algorithm besides bcrypt (default). You can use - # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, - # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) - # and :restful_authentication_sha1 (then you should set stretches to 10, and copy - # REST_AUTH_SITE_KEY to pepper) - # config.encryptor = :sha512 - - # ==> Configuration for :token_authenticatable - # Defines name of the authentication token params key - # config.token_authentication_key = :auth_token - - # ==> Scopes configuration - # Turn scoped views on. Before rendering "sessions/new", it will first check for - # "users/sessions/new". It's turned off by default because it's slower if you - # are using only default views. - # config.scoped_views = false - - # Configure the default scope given to Warden. By default it's the first - # devise role declared in your routes (usually :user). - # config.default_scope = :user - - # Set this configuration to false if you want /users/sign_out to sign out - # only the current scope. By default, Devise signs out all scopes. - # config.sign_out_all_scopes = true - - # ==> Navigation configuration - # Lists the formats that should be treated as navigational. Formats like - # :html, should redirect to the sign in page when the user does not have - # access, but formats like :xml or :json, should return 401. - # - # If you have any extra navigational formats, like :iphone or :mobile, you - # should add them to the navigational formats lists. - # - # The "*/*" below is required to match Internet Explorer requests. - # config.navigational_formats = ["*/*", :html] - - # The default HTTP method used to sign out a resource. Default is :delete. - config.sign_out_via = :get - - - config.secret_key = ENV.fetch('DEVISE_SECRET_KEY') - - # ==> Warden configuration - # If you want to use other strategies, that are not supported by Devise, or - # change the failure app, you can configure them inside the config.warden block. - # - # config.warden do |manager| - # manager.intercept_401 = false - # manager.default_strategies(:scope => :user).unshift :some_external_strategy - # end - - # ==> Mountable engine configurations - # When using Devise inside an engine, let's call it `MyEngine`, and this engine - # is mountable, there are some extra configurations to be taken into account. - # The following options are available, assuming the engine is mounted as: - # - # mount MyEngine, at: "/my_engine" - # - # The router that invoked `devise_for`, in the example above, would be: - # config.router_name = :my_engine - # - # When using omniauth, Devise cannot automatically set Omniauth path, - # so you need to do it manually. For the users scope, it would be: - # config.omniauth_path_prefix = "/my_engine/users/auth" - - config.parent_mailer = 'BaseMailer' + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in Devise::Mailer, + # note that it will be overwritten if you use your own mailer class with default "from" parameter. + config.mailer_sender = Settings.devise.mailer_sender + + # Configure the class responsible to send e-mails. + # config.mailer = "Devise::Mailer" + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require "devise/orm/active_record" + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating a user. The default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating a user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + # config.authentication_keys = [ :email ] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # Configure which authentication keys should be case-insensitive. + # These keys will be downcased upon creating or modifying a user and when used + # to authenticate or find a user. Default is :email. + config.case_insensitive_keys = [:email] + + # Configure which authentication keys should have whitespace stripped. + # These keys will have whitespace before and after removed upon creating or + # modifying a user and when used to authenticate or find a user. Default is :email. + config.strip_whitespace_keys = [:email] + + # Tell if authentication through request.params is enabled. True by default. + # It can be set to an array that will enable params authentication only for the + # given strategies, for example, `config.params_authenticatable = [:database]` will + # enable it only for database (email + password) authentication. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Basic Auth is enabled. False by default. + # It can be set to an array that will enable http authentication only for the + # given strategies, for example, `config.http_authenticatable = [:token]` will + # enable it only for token authentication. + config.http_authenticatable = true + + # If http headers should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. "Application" by default. + # config.http_authentication_realm = "Application" + + # It will change confirmation, password recovery and other workflows + # to behave the same regardless if the e-mail provided was right or wrong. + # Does not affect registerable. + # config.paranoid = true + + # By default Devise will store the user in session. You can skip storage for + # :http_auth and :token_auth by adding those symbols to the array below. + # Notice that if you are skipping storage for all authentication paths, you + # may want to disable generating routes to Devise's sessions controller by + # passing :skip => :sessions to `devise_for` in your config/routes.rb + config.skip_session_storage = [:http_auth] + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 10. If + # using other encryptors, it sets how many times you want the password re-encrypted. + # + # Limiting the stretches to just one in testing will increase the performance of + # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use + # a value less than 10 in other environments. + config.stretches = Rails.env.test? ? 1 : 10 + + # ==> Configuration for :confirmable + # A period that the user is allowed to access the website even without + # confirming his account. For instance, if set to 2.days, the user will be + # able to access the website for two days without confirming his account, + # access will be blocked just in the third day. Default is 0.days, meaning + # the user cannot access the website without confirming his account. + # config.allow_unconfirmed_access_for = 2.days + + # If true, requires any email changes to be confirmed (exactly the same way as + # initial account confirmation) to be applied. Requires additional unconfirmed_email + # db field (see migrations). Until confirmed new email is stored in + # unconfirmed email column, and copied to email column on successful confirmation. + config.reconfirmable = true + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [ :email ] + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # Options to be passed to the created cookie. For instance, you can set + # :secure => true in order to force SSL only cookies. + # config.rememberable_options = {} + + # ==> Configuration for :validatable + # Range for password length. Default is 6..128. + # config.password_length = 6..128 + + # Email regex used to validate email formats. It simply asserts that + # an one (and only one) @ exists in the given string. This is mainly + # to give user feedback and not to assert the e-mail validity. + # config.email_regexp = /\A[^@]+@[^@]+\z/ + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # If true, expires auth token on session timeout. + # config.expire_auth_token_on_timeout = false + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + config.lock_strategy = :failed_attempts + + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [ :email ] + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + config.unlock_strategy = :email + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + config.maximum_attempts = 10 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [ :email ] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 6.hours + + # ==> Configuration for :encryptable + # Allow you to use another encryption algorithm besides bcrypt (default). You can use + # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, + # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) + # and :restful_authentication_sha1 (then you should set stretches to 10, and copy + # REST_AUTH_SITE_KEY to pepper) + # config.encryptor = :sha512 + + # ==> Configuration for :token_authenticatable + # Defines name of the authentication token params key + # config.token_authentication_key = :auth_token + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + # config.scoped_views = false + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). + # config.default_scope = :user + + # Set this configuration to false if you want /users/sign_out to sign out + # only the current scope. By default, Devise signs out all scopes. + # config.sign_out_all_scopes = true + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html, should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. + # + # The "*/*" below is required to match Internet Explorer requests. + # config.navigational_formats = ["*/*", :html] + + # The default HTTP method used to sign out a resource. Default is :delete. + config.sign_out_via = :get + + config.secret_key = ENV.fetch("DEVISE_SECRET_KEY") + + # ==> Warden configuration + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. + # + # config.warden do |manager| + # manager.intercept_401 = false + # manager.default_strategies(:scope => :user).unshift :some_external_strategy + # end + + # ==> Mountable engine configurations + # When using Devise inside an engine, let's call it `MyEngine`, and this engine + # is mountable, there are some extra configurations to be taken into account. + # The following options are available, assuming the engine is mounted as: + # + # mount MyEngine, at: "/my_engine" + # + # The router that invoked `devise_for`, in the example above, would be: + # config.router_name = :my_engine + # + # When using omniauth, Devise cannot automatically set Omniauth path, + # so you need to do it manually. For the users scope, it would be: + # config.omniauth_path_prefix = "/my_engine/users/auth" + + config.parent_mailer = "BaseMailer" end ActiveSupport.on_load(:devise_failure_app) do @@ -236,10 +234,10 @@ class FailureApp # we don't every want to return WWW-Authenticate because we never want a popup. def http_auth self.status = 401 - #self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header? + # self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header? self.content_type = request.format.to_s self.response_body = http_auth_body end end end -end \ No newline at end of file +end diff --git a/config/initializers/email_jobs.rb b/config/initializers/email_jobs.rb index a327a3a2e..a236b47dd 100644 --- a/config/initializers/email_jobs.rb +++ b/config/initializers/email_jobs.rb @@ -1,2 +1,2 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -MAX_EMAIL_JOB_ATTEMPTS = Rails.env == 'production' ? 50 : 2 \ No newline at end of file +MAX_EMAIL_JOB_ATTEMPTS = Rails.env.production? ? 50 : 2 diff --git a/config/initializers/fee_switchover.rb b/config/initializers/fee_switchover.rb index b881b310b..1d995b4b4 100644 --- a/config/initializers/fee_switchover.rb +++ b/config/initializers/fee_switchover.rb @@ -1,2 +1,2 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -FEE_SWITCHOVER_TIME = ENV['FEE_SWITCHOVER_TIME'] && ENV['FEE_SWITCHOVER_TIME'].to_i != 0 && Time.at(ENV['FEE_SWITCHOVER_TIME'].to_i) \ No newline at end of file +FEE_SWITCHOVER_TIME = ENV["FEE_SWITCHOVER_TIME"] && ENV["FEE_SWITCHOVER_TIME"].to_i != 0 && Time.at(ENV["FEE_SWITCHOVER_TIME"].to_i) diff --git a/config/initializers/geocode.rb b/config/initializers/geocode.rb index aa034b73e..78500aad9 100644 --- a/config/initializers/geocode.rb +++ b/config/initializers/geocode.rb @@ -3,6 +3,6 @@ cache: Rails.cache, lookup: :google, use_https: true, - api_key: ENV['GOOGLE_API_KEY'], + api_key: ENV["GOOGLE_API_KEY"], timeout: 10 }) diff --git a/config/initializers/immutable_extensions.rb b/config/initializers/immutable_extensions.rb index dcac69d50..efe04fbe3 100644 --- a/config/initializers/immutable_extensions.rb +++ b/config/initializers/immutable_extensions.rb @@ -1,9 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # Immutable extesions/modifications -require 'immutable' +require "immutable" # Default Immutable to_json methods don't work right module ProperJson - def to_json(options={}) + def to_json(options = {}) Immutable.to_ruby(self).to_json(options) end end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 0c8ca6e3f..90d3b97f5 100755 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -12,7 +12,7 @@ # These inflection rules are supported but not enabled by default: ActiveSupport::Inflector.inflections(:en) do |inflect| - inflect.acronym 'UUID' - inflect.acronym 'HTML' - inflect.acronym 'HTTParty' + inflect.acronym "UUID" + inflect.acronym "HTML" + inflect.acronym "HTTParty" end diff --git a/config/initializers/js_routes.rb b/config/initializers/js_routes.rb index b1f92216f..3d3e98368 100644 --- a/config/initializers/js_routes.rb +++ b/config/initializers/js_routes.rb @@ -3,8 +3,8 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE JsRoutes.setup do |c| - # Setup your JS module system: - # ESM, CJS, AMD, UMD or nil - c.module_type = 'CJS' - c.camel_case = true + # Setup your JS module system: + # ESM, CJS, AMD, UMD or nil + c.module_type = "CJS" + c.camel_case = true end diff --git a/config/initializers/lock_manager.rb b/config/initializers/lock_manager.rb index e45cbf932..7dedf1b86 100644 --- a/config/initializers/lock_manager.rb +++ b/config/initializers/lock_manager.rb @@ -1,4 +1,3 @@ - class LockManager DEFAULT_OPTIONS = { acquisition_timeout: 30, @@ -14,12 +13,12 @@ def initialize(options = {}) @retry_count = (@options[:acquisition_timeout] / @options[:acquisition_delay].to_f).ceil end - def self.with_transaction_lock(lock_name, options={}) + def self.with_transaction_lock(lock_name, options = {}) lock = new(options) lock_id = Zlib.crc32(lock_name.to_s) ActiveRecord::Base.transaction do - lock.retry_with_timeout do - if (ActiveRecord::Base.connection.execute("SELECT pg_try_advisory_xact_lock(#{lock_id})").values[0][0]) + lock.retry_with_timeout do + if ActiveRecord::Base.connection.execute("SELECT pg_try_advisory_xact_lock(#{lock_id})").values[0][0] yield break end @@ -27,13 +26,12 @@ def self.with_transaction_lock(lock_name, options={}) end end - def retry_with_timeout start = Time.now.to_f @retry_count.times do elapsed = Time.now.to_f - start raise "elapsed of #{elasped} is longer than max timeout of #{@options[:acquisition_timeout]}" if elapsed >= @options[:acquisition_timeout] - + result = yield return if result sleep(rand(@options[:acquisition_delay] * 1000).to_f / 1000) diff --git a/config/initializers/log_rage.rb b/config/initializers/log_rage.rb index f76666a73..2aaac6d74 100644 --- a/config/initializers/log_rage.rb +++ b/config/initializers/log_rage.rb @@ -1,15 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later Rails.application.configure do - if (Rails.env != 'test') + if !Rails.env.test? - - config.lograge.enabled = true - # add time to lograge - config.lograge.custom_options = lambda do |event| - { time: event.time, - exception: event.payload[:exception], # ["ExceptionClass", "the message"] - exception_object: event.payload[:exception_object] # the exception instance - } - end + config.lograge.enabled = true + # add time to lograge + config.lograge.custom_options = lambda do |event| + {time: event.time, + exception: event.payload[:exception], # ["ExceptionClass", "the message"] + exception_object: event.payload[:exception_object]} # the exception instance + end end -end \ No newline at end of file +end diff --git a/config/initializers/mailchimp.rb b/config/initializers/mailchimp.rb index 5d5cd24aa..521023be9 100644 --- a/config/initializers/mailchimp.rb +++ b/config/initializers/mailchimp.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'mailchimp' +require "mailchimp" Mailchimp.config({ - :api_key => ENV['MAILCHIMP_API_KEY'], - :username => ENV['MAILCHIMP_USERNAME'] + api_key: ENV["MAILCHIMP_API_KEY"], + username: ENV["MAILCHIMP_USERNAME"] }) diff --git a/config/initializers/pg_type_map.rb b/config/initializers/pg_type_map.rb index 931e61072..60aba4204 100644 --- a/config/initializers/pg_type_map.rb +++ b/config/initializers/pg_type_map.rb @@ -3,4 +3,3 @@ Qx.config(type_map: PG::BasicTypeMapForResults.new(ActiveRecord::Base.connection.raw_connection)) Qx.execute("SET TIME ZONE utc") end - diff --git a/config/initializers/premailer.rb b/config/initializers/premailer.rb index b36bd3b8e..625f190ba 100644 --- a/config/initializers/premailer.rb +++ b/config/initializers/premailer.rb @@ -1,2 +1,2 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -Premailer::Rails.config.merge!(preserve_style_attribute:true) +Premailer::Rails.config.merge!(preserve_style_attribute: true) diff --git a/config/initializers/rabl_init.rb b/config/initializers/rabl_init.rb index acd7ebaa0..ec861f601 100644 --- a/config/initializers/rabl_init.rb +++ b/config/initializers/rabl_init.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rabl' +require "rabl" Rabl.configure do |config| - config.enable_json_callbacks = true + config.enable_json_callbacks = true end diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index 7663ec1c8..1ff760a08 100755 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -5,6 +5,6 @@ # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. -Rails.application.config.secret_token = ENV.fetch('SECRET_TOKEN') +Rails.application.config.secret_token = ENV.fetch("SECRET_TOKEN") -Rails.application.config.secret_key_base = ENV.fetch('SECRET_KEY_BASE') +Rails.application.config.secret_key_base = ENV.fetch("SECRET_KEY_BASE") diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index fa6874a24..3f4e05d55 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,11 +1,11 @@ # Be sure to restart your server when you modify this file. if Rails.env.development? - Rails.application.config.session_store :cookie_store, key: '_commitchange_session' + Rails.application.config.session_store :cookie_store, key: "_commitchange_session" elsif Rails.env.staging? || Rails.env.production? - Rails.application.config.session_store :redis_store, servers: [ENV['OPENREDIS_URL']], + Rails.application.config.session_store :redis_store, servers: [ENV["OPENREDIS_URL"]], expire_after: 12.hours, namespace: "_#{Rails.application.class.module_parent_name.downcase}_session" else - Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 12.hours + Rails.application.config.session_store ActionDispatch::Session::CacheStore, expire_after: 12.hours end diff --git a/config/initializers/stripe.rb b/config/initializers/stripe.rb index 42abc0a33..50a7e7c5c 100644 --- a/config/initializers/stripe.rb +++ b/config/initializers/stripe.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'stripe' +require "stripe" -Stripe.api_key = Settings.payment_provider.stripe_private_key; -Stripe.api_version = '2017-06-05' +Stripe.api_key = Settings.payment_provider.stripe_private_key +Stripe.api_version = "2017-06-05" Stripe.logger = Rails.logger diff --git a/config/initializers/throttling.rb b/config/initializers/throttling.rb index 1e2c0feb7..a9a2af04f 100644 --- a/config/initializers/throttling.rb +++ b/config/initializers/throttling.rb @@ -20,24 +20,23 @@ def reset_count(unprefixed_key, period) epoch_time = Time.now.to_i # Add 1 to expires_in to avoid timing error: http://git.io/i1PHXA expires_in = period - (epoch_time % period) + 1 - key = "#{prefix}:#{(epoch_time/period).to_i}:#{unprefixed_key}" - store.write(key, 0, :expires_in => expires_in) + key = "#{prefix}:#{(epoch_time / period).to_i}:#{unprefixed_key}" + store.write(key, 0, expires_in: expires_in) end end def run_throttle? - Rails.env != 'test' || (defined? FORCE_THROTTLE && FORCE_THROTTLE) + !Rails.env.test? || (defined? FORCE_THROTTLE && FORCE_THROTTLE) end - -if ENV['THROTTLE_CARD_L1_LIMIT'] && ENV['THROTTLE_CARD_L1_PERIOD'] - Rack::Attack.throttle('post to add card by supporter LEVEL 1', limit:ENV['THROTTLE_CARD_L1_LIMIT'].to_i, period: ENV['THROTTLE_CARD_L1_PERIOD'].to_i) do |req| +if ENV["THROTTLE_CARD_L1_LIMIT"] && ENV["THROTTLE_CARD_L1_PERIOD"] + Rack::Attack.throttle("post to add card by supporter LEVEL 1", limit: ENV["THROTTLE_CARD_L1_LIMIT"].to_i, period: ENV["THROTTLE_CARD_L1_PERIOD"].to_i) do |req| ret = nil - if run_throttle? && req.path == '/cards' && req.post? + if run_throttle? && req.path == "/cards" && req.post? begin json = JSON.parse(req.body.string) - if json['card']['holder_type'] == 'Supporter' - ret = json['card']['holder_id'] + if json["card"]["holder_type"] == "Supporter" + ret = json["card"]["holder_id"] end rescue req.body.rewind @@ -48,14 +47,14 @@ def run_throttle? end end -if ENV['THROTTLE_CARD_L2_LIMIT'] && ENV['THROTTLE_CARD_L2_PERIOD'] - Rack::Attack.throttle('post to add card by supporter LEVEL 2', limit:ENV['THROTTLE_CARD_L2_LIMIT'].to_i, period: ENV['THROTTLE_CARD_L2_PERIOD'].to_i) do |req| +if ENV["THROTTLE_CARD_L2_LIMIT"] && ENV["THROTTLE_CARD_L2_PERIOD"] + Rack::Attack.throttle("post to add card by supporter LEVEL 2", limit: ENV["THROTTLE_CARD_L2_LIMIT"].to_i, period: ENV["THROTTLE_CARD_L2_PERIOD"].to_i) do |req| ret = nil - if run_throttle? && req.path == '/cards' && req.post? + if run_throttle? && req.path == "/cards" && req.post? begin json = JSON.parse(req.body.string) - if json['card']['holder_type'] == 'Supporter' - ret = json['card']['holder_id'] + if json["card"]["holder_type"] == "Supporter" + ret = json["card"]["holder_id"] end rescue req.body.rewind @@ -71,7 +70,7 @@ def run_throttle? if run_throttle? && req.path =~ /\/nonprofits\/(.*)\/supporters/ && req.post? begin json = JSON.parse(req.body.string) - ret = json['email'] =~ /.*@itymail.com/ + ret = json["email"] =~ /.*@itymail.com/ rescue req.body.rewind end @@ -80,16 +79,14 @@ def run_throttle? ret end - -if ENV['THROTTLE_SUPPORTER_LIMIT'] && ENV['THROTTLE_SUPPORTER_PERIOD'] - Rack::Attack.throttle('post to supporter', limit:ENV['THROTTLE_SUPPORTER_LIMIT'].to_i, period: ENV['THROTTLE_SUPPORTER_PERIOD'].to_i) do |req| +if ENV["THROTTLE_SUPPORTER_LIMIT"] && ENV["THROTTLE_SUPPORTER_PERIOD"] + Rack::Attack.throttle("post to supporter", limit: ENV["THROTTLE_SUPPORTER_LIMIT"].to_i, period: ENV["THROTTLE_SUPPORTER_PERIOD"].to_i) do |req| ret = nil - if run_throttle? && req.path =~ /\/nonprofits\/(.*)\/supporters/ && req.post? begin json = JSON.parse(req.body.string) - ret = json['email'] + ret = json["email"] rescue req.body.rewind end @@ -99,7 +96,6 @@ def run_throttle? end end - Rack::Attack.throttled_response = lambda do |env| - [ 429, {'Content-Type' => 'application/json'}, [JSON.generate({'error': "I'm sorry; something went wrong. Please contact support@commitchange.com for help."})]] + [429, {"Content-Type" => "application/json"}, [JSON.generate({error: "I'm sorry; something went wrong. Please contact support@commitchange.com for help."})]] end diff --git a/config/initializers/time.rb b/config/initializers/time.rb index ebef3a837..eb17d0407 100644 --- a/config/initializers/time.rb +++ b/config/initializers/time.rb @@ -1,6 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -ENV['TZ'] = 'UTC' -Time.zone = 'UTC' +ENV["TZ"] = "UTC" +Time.zone = "UTC" module Chronic def self.time_class diff --git a/config/initializers/timeout.rb b/config/initializers/timeout.rb index 41aab386f..723812b03 100644 --- a/config/initializers/timeout.rb +++ b/config/initializers/timeout.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -timeout = Integer(ENV['WEB_TIMEOUT'] || 15) -if ENV['RAILS_ENV'] == 'development' || ENV['IDE_PROCESS_DISPATCHER'] +timeout = Integer(ENV["WEB_TIMEOUT"] || 15) +if ENV["RAILS_ENV"] == "development" || ENV["IDE_PROCESS_DISPATCHER"] timeout = 10000 end -Rack::Timeout.timeout = timeout # seconds \ No newline at end of file +Rack::Timeout.timeout = timeout # seconds diff --git a/config/initializers/to_deprecated_h.rb b/config/initializers/to_deprecated_h.rb index 3316d500d..578e390cc 100644 --- a/config/initializers/to_deprecated_h.rb +++ b/config/initializers/to_deprecated_h.rb @@ -1,3 +1,3 @@ ActiveSupport.on_load(:action_controller_base) do - require 'to_deprecated_h' -end \ No newline at end of file + require "to_deprecated_h" +end diff --git a/config/puma.rb b/config/puma.rb index 3caa7eead..5e1eeedf8 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'barnes' +require "barnes" # Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. @@ -19,7 +19,7 @@ # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # -port ENV.fetch("PORT") { 5000 } +port ENV.fetch("PORT") { 5000 } # Specifies the `environment` that Puma will run in. # @@ -43,15 +43,17 @@ # you need to make sure to reconnect any threads in the `on_worker_boot` # block. # -preload_app! if env != 'development' +preload_app! if env != "development" # If you are preloading your application and using Active Record, it's # recommended that you close any connections to the database before workers # are forked to prevent connection leakage. # -before_fork do - ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) -end if env != 'development' +if env != "development" + before_fork do + ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) + end +end # The code in the `on_worker_boot` will be called if you are using # clustered mode by specifying a number of `workers`. After each worker diff --git a/config/routes.rb b/config/routes.rb index 6b5e60264..9b2013f35 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later Rails.application.routes.draw do - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - if Rails.env == 'development' - get '/button_debug/embedded' => 'button_debug#embedded' - get '/button_debug/button' => 'button_debug#button' - get '/button_debug/embedded/:id' => 'button_debug#embedded' - get '/button_debug/button/:id' => 'button_debug#button' + if Rails.env.development? + get "/button_debug/embedded" => "button_debug#embedded" + get "/button_debug/button" => "button_debug#button" + get "/button_debug/embedded/:id" => "button_debug#embedded" + get "/button_debug/button/:id" => "button_debug#button" end - get 'onboard' => 'onboard#index' + get "onboard" => "onboard#index" defaults format: :json do # they're APIs, you have to use JSON namespace :api do @@ -31,7 +31,7 @@ resources :settings, only: [:index] resources :campaign_gifts, only: [:create] resource :cards, only: %i[create update destroy] - resource :direct_debit_details, path: 'sepa', controller: :direct_debit_details, only: [:create] + resource :direct_debit_details, path: "sepa", controller: :direct_debit_details, only: [:create] # Creating presigned posts for direct-to-S3 upload resources :aws_presigned_posts, only: [:create] @@ -48,7 +48,7 @@ end end - namespace :nonprofits, path: 'nonprofits/:nonprofit_id' do + namespace :nonprofits, path: "nonprofits/:nonprofit_id" do resource :stripe_account, only: [:index] do get :index, format: :json get :verification @@ -139,10 +139,10 @@ post :send_code end - post 'tracking', controller: 'trackings', action: 'create' + post "tracking", controller: "trackings", action: "create" end - namespace :campaigns, path: '/nonprofits/:nonprofit_id/campaigns/:campaign_id/admin', only: [] do + namespace :campaigns, path: "/nonprofits/:nonprofit_id/campaigns/:campaign_id/admin", only: [] do resources :supporters, only: [:index] resources :donations, only: [:index] resources :campaign_gift_options, only: [:index] @@ -223,7 +223,7 @@ get :dashboard get :dashboard_metrics get :payment_history - post :donate, as: 'create_donation' + post :donate, as: "create_donation" end end @@ -232,32 +232,32 @@ end devise_for :users, - controllers: { - sessions: 'users/sessions', - registrations: 'users/registrations', - confirmations: 'users/confirmations' - } + controllers: { + sessions: "users/sessions", + registrations: "users/registrations", + confirmations: "users/confirmations" + } devise_scope :user do - match '/sign_in' => 'users/sessions#new', via: %i[get post] - match '/signup' => 'devise/registrations#new', via: %i[get post] - post '/confirm' => 'users/confirmations#confirm', via: [:get] - match '/users/is_confirmed' => 'users/confirmations#is_confirmed', via: %i[get post] - match '/users/exists' => 'users/confirmations#exists', via: [:get] - post '/users/confirm_auth', action: :confirm_auth, controller: 'users/sessions', via: %i[get post] + match "/sign_in" => "users/sessions#new", :via => %i[get post] + match "/signup" => "devise/registrations#new", :via => %i[get post] + post "/confirm" => "users/confirmations#confirm", :via => [:get] + match "/users/is_confirmed" => "users/confirmations#is_confirmed", :via => %i[get post] + get "/users/exists" => "users/confirmations#exists" + post "/users/confirm_auth", action: :confirm_auth, controller: "users/sessions", via: %i[get post] end # Super admin - get '/admin' => 'super_admins#index', :as => 'admin' - get '/admin/search-nonprofits' => 'super_admins#search_nonprofits' - get '/admin/search-profiles' => 'super_admins#search_profiles' - get '/admin/search-fullcontact' => 'super_admins#search_fullcontact' - get '/admin/recurring-donations-without-cards' => 'super_admins#recurring_donations_without_cards' - get '/admin/export_supporters_with_rds' => 'super_admins#export_supporters_with_rds' - get '/admin/resend_user_confirmation' => 'super_admins#resend_user_confirmation' + get "/admin" => "super_admins#index", :as => "admin" + get "/admin/search-nonprofits" => "super_admins#search_nonprofits" + get "/admin/search-profiles" => "super_admins#search_profiles" + get "/admin/search-fullcontact" => "super_admins#search_fullcontact" + get "/admin/recurring-donations-without-cards" => "super_admins#recurring_donations_without_cards" + get "/admin/export_supporters_with_rds" => "super_admins#export_supporters_with_rds" + get "/admin/resend_user_confirmation" => "super_admins#resend_user_confirmation" # Events - get '/events' => 'events#index' - get '/events/:event_slug' => 'events#show' + get "/events" => "events#index" + get "/events/:event_slug" => "events#show" defaults format: :json do post "/webhooks/stripe/receive" => "webhooks/stripe#receive" @@ -265,37 +265,37 @@ end # Nonprofits - get ':state_code/:city/:name' => 'nonprofits#show', :as => :nonprofit_location - get ':state_code/:city/:name/donate' => 'nonprofits#donate', :as => :nonprofit_donation - get ':state_code/:city/:name/button' => 'nonprofits/button#guided' + get ":state_code/:city/:name" => "nonprofits#show", :as => :nonprofit_location + get ":state_code/:city/:name/donate" => "nonprofits#donate", :as => :nonprofit_donation + get ":state_code/:city/:name/button" => "nonprofits/button#guided" # Campaigns - get ':state_code/:city/:name/campaigns' => 'campaigns#index' - get ':state_code/:city/:name/campaigns/:campaign_slug' => 'campaigns#show', :as => :campaign_loc - get ':state_code/:city/:name/campaigns/:campaign_slug/supporters' => 'campaigns/supporters#index' - get '/peer-to-peer' => 'campaigns#peer_to_peer' + get ":state_code/:city/:name/campaigns" => "campaigns#index" + get ":state_code/:city/:name/campaigns/:campaign_slug" => "campaigns#show", :as => :campaign_loc + get ":state_code/:city/:name/campaigns/:campaign_slug/supporters" => "campaigns/supporters#index" + get "/peer-to-peer" => "campaigns#peer_to_peer" # Events - get ':state_code/:city/:name/events' => 'events#index' - get ':state_code/:city/:name/events/:event_slug' => 'events#show', as: :slugged_event - get ':state_code/:city/:name/events/:event_slug/stats' => 'events#stats' - get ':state_code/:city/:name/events/:event_slug/tickets' => 'tickets#index' + get ":state_code/:city/:name/events" => "events#index" + get ":state_code/:city/:name/events/:event_slug" => "events#show", :as => :slugged_event + get ":state_code/:city/:name/events/:event_slug/stats" => "events#stats" + get ":state_code/:city/:name/events/:event_slug/tickets" => "tickets#index" # get '/events' => 'events#index' # Dashboard - get ':state_code/:city/:name/dashboard' => 'nonprofits#dashboard', as: :np_dashboard + get ":state_code/:city/:name/dashboard" => "nonprofits#dashboard", :as => :np_dashboard # Misc - get '/pages/wp-plugin', to: redirect('/help/wordpress-plugin') #temporary, until WP plugin updated + get "/pages/wp-plugin", to: redirect("/help/wordpress-plugin") # temporary, until WP plugin updated # Maps - get '/maps/all-npos' => 'maps#all_npos' - get '/maps/all-supporters' => 'maps#all_supporters' - get '/maps/all-npo-supporters' => 'maps#all_npo_supporters' - get '/maps/specific-npo-supporters' => 'maps#specific_npo_supporters' + get "/maps/all-npos" => "maps#all_npos" + get "/maps/all-supporters" => "maps#all_supporters" + get "/maps/all-npo-supporters" => "maps#all_npo_supporters" + get "/maps/specific-npo-supporters" => "maps#specific_npo_supporters" # Mailchimp Landing - get '/mailchimp-landing' => 'nonprofits/nonprofit_keys#mailchimp_landing' + get "/mailchimp-landing" => "nonprofits/nonprofit_keys#mailchimp_landing" # Will create a slugged route for `Nonprofit`. So, if `nonprofit` is a `Nonprofit` with a state_code_slug: wi, # city_slug: appleton and slug: sample-commitchange-nonprofit, then `slugged_nonprofit_path(nonprofit)` would return: @@ -305,16 +305,16 @@ end # Will create a slugged route for `Nonprofit`'s dashboard. So, if `nonprofit` is a `Nonprofit` with a state_code_slug: wi, - # city_slug: appleton and slug: sample-commitchange-nonprofit, then `slugged_nonprofit_dashboard_path(nonprofit)` would + # city_slug: appleton and slug: sample-commitchange-nonprofit, then `slugged_nonprofit_dashboard_path(nonprofit)` would # return: /wi/appleton/sample-commitchange-nonprofit/dashboard direct(:slugged_nonprofit_dashboard) do |model, options| np_dashboard_path(state_code: model.state_code_slug, city: model.city_slug, name: model.slug, **options) end # Webhooks - get '/static/terms_and_privacy' => 'static#terms_and_privacy' - get '/static/ccs' => 'static#ccs' - get '/cloudflare_errors/under_attack' => 'cloudflare_errors#under_attack' + get "/static/terms_and_privacy" => "static#terms_and_privacy" + get "/static/ccs" => "static#ccs" + get "/cloudflare_errors/under_attack" => "cloudflare_errors#under_attack" - root :to => 'front#index' + root to: "front#index" end diff --git a/config/spring.rb b/config/spring.rb index c9119b40c..9fa7863f9 100644 --- a/config/spring.rb +++ b/config/spring.rb @@ -1,6 +1,6 @@ -%w( +%w[ .ruby-version .rbenv-vars tmp/restart.txt tmp/caching-dev.txt -).each { |path| Spring.watch(path) } +].each { |path| Spring.watch(path) } diff --git a/db/migrate/20170307222633_add_indexes_for_payment_and_supporter_queries.rb b/db/migrate/20170307222633_add_indexes_for_payment_and_supporter_queries.rb index 36b5ac5d7..4ca84e457 100644 --- a/db/migrate/20170307222633_add_indexes_for_payment_and_supporter_queries.rb +++ b/db/migrate/20170307222633_add_indexes_for_payment_and_supporter_queries.rb @@ -2,7 +2,7 @@ class AddIndexesForPaymentAndSupporterQueries < ActiveRecord::Migration def up Qx.transaction do - Qx.execute(%Q( + Qx.execute(%( CREATE INDEX IF NOT EXISTS payments_date ON payments (date); CREATE INDEX IF NOT EXISTS payments_gross_amount ON payments (gross_amount); CREATE INDEX IF NOT EXISTS payments_kind ON payments (kind); @@ -29,7 +29,7 @@ def up end def down - Qx.execute(%Q( + Qx.execute(%( DROP INDEX IF EXISTS payments_date; DROP INDEX IF EXISTS payments_gross_amount; DROP INDEX IF EXISTS payments_kind; diff --git a/db/migrate/20170307223525_drop_all_cruft.rb b/db/migrate/20170307223525_drop_all_cruft.rb index 92361fc73..bde7cf990 100644 --- a/db/migrate/20170307223525_drop_all_cruft.rb +++ b/db/migrate/20170307223525_drop_all_cruft.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class DropAllCruft < ActiveRecord::Migration def change - Qx.execute(%Q( + Qx.execute(%( DROP FUNCTION IF EXISTS update_payment_donations_search_vectors(); DROP FUNCTION IF EXISTS supporters_insert_trigger(); DROP FUNCTION IF EXISTS update_payment_search_vectors(); @@ -22,7 +22,7 @@ def change end def down - Qx.execute(%Q( + Qx.execute(%( CREATE FUNCTION update_payment_donations_search_vectors() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN @@ -42,9 +42,9 @@ def down , donations.designation , donations.dedication ) AS search_blob -FROM payments +FROM payments LEFT OUTER JOIN supporters - ON payments.supporter_id=supporters.id + ON payments.supporter_id=supporters.id LEFT OUTER JOIN donations ON payments.donation_id=donations.id WHERE (payments.donation_id=NEW.id)) AS data @@ -53,7 +53,7 @@ def down END $$; )) - Qx.execute(%Q( + Qx.execute(%( CREATE FUNCTION supporters_insert_trigger() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -63,7 +63,7 @@ def down END; $$; )) - Qx.execute(%Q( + Qx.execute(%( CREATE FUNCTION update_payment_search_vectors() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN @@ -83,9 +83,9 @@ def down , donations.designation , donations.dedication ) AS search_blob -FROM payments +FROM payments LEFT OUTER JOIN supporters - ON payments.supporter_id=supporters.id + ON payments.supporter_id=supporters.id LEFT OUTER JOIN donations ON payments.donation_id=donations.id WHERE (payments.id=NEW.id)) AS data @@ -95,7 +95,7 @@ def down )) - Qx.execute(%Q( + Qx.execute(%( CREATE FUNCTION update_payment_supporters_search_vectors() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN @@ -115,9 +115,9 @@ def down , donations.designation , donations.dedication ) AS search_blob -FROM payments +FROM payments LEFT OUTER JOIN supporters - ON payments.supporter_id=supporters.id + ON payments.supporter_id=supporters.id LEFT OUTER JOIN donations ON payments.donation_id=donations.id WHERE (payments.supporter_id=NEW.id)) AS data @@ -126,8 +126,7 @@ def down END $$; )) - - Qx.execute(%Q( + Qx.execute(%( CREATE FUNCTION update_supporter_search_vectors() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN @@ -148,14 +147,14 @@ def down , payments.kind , payments.towards ) AS search_blob -FROM supporters +FROM supporters LEFT OUTER JOIN payments - ON payments.supporter_id=supporters.id + ON payments.supporter_id=supporters.id LEFT OUTER JOIN donations - ON donations.supporter_id=supporters.id + ON donations.supporter_id=supporters.id LEFT OUTER JOIN ( SELECT string_agg(value::text, ' ') AS value, supporter_id -FROM custom_field_joins +FROM custom_field_joins GROUP BY supporter_id) AS custom_field_joins ON custom_field_joins.supporter_id=supporters.id WHERE (supporters.id=NEW.id)) AS data @@ -164,8 +163,7 @@ def down END $$; )) - - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE billing_customers ( id integer NOT NULL, card_name character varying(255), @@ -177,7 +175,7 @@ def down )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE coupons ( id integer NOT NULL, name character varying(255), @@ -189,7 +187,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE dedications ( id integer NOT NULL, donation_id integer, @@ -199,7 +197,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE email_drafts ( id integer NOT NULL, nonprofit_id integer, @@ -211,7 +209,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE image_points ( id integer NOT NULL, image_name character varying(255), @@ -226,7 +224,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE pg_search_documents ( id integer NOT NULL, content text, @@ -238,7 +236,7 @@ def down )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE prospect_events ( id integer NOT NULL, event character varying(255), @@ -249,7 +247,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE prospect_visit_params ( id integer NOT NULL, key character varying(255), @@ -258,7 +256,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE prospect_visits ( id integer NOT NULL, pathname text, @@ -268,7 +266,7 @@ def down ); )) - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE prospects ( id integer NOT NULL, ip_address character varying(255), @@ -282,8 +280,7 @@ def down ); )) - - Qx.execute(%Q( + Qx.execute(%( CREATE TABLE recommendations ( id integer NOT NULL, nonprofit_id integer, @@ -293,9 +290,5 @@ def down updated_at timestamp without time zone NOT NULL ); )) - - - end - end diff --git a/db/migrate/20170314193744_normalize_start_and_end_datetimes_for_events_and_campaigns.rb b/db/migrate/20170314193744_normalize_start_and_end_datetimes_for_events_and_campaigns.rb index 15227178b..8836d9a86 100644 --- a/db/migrate/20170314193744_normalize_start_and_end_datetimes_for_events_and_campaigns.rb +++ b/db/migrate/20170314193744_normalize_start_and_end_datetimes_for_events_and_campaigns.rb @@ -5,7 +5,7 @@ def up add_column :events, :end_datetime, :datetime add_column :campaigns, :end_datetime, :datetime Qx.update(:events) - .set(%Q(start_datetime = ("date" + start_time), end_datetime = ("date" + end_time))) + .set(%(start_datetime = ("date" + start_time), end_datetime = ("date" + end_time))) .where("created_at > '2012-01-01'") .execute Qx.update(:campaigns) @@ -18,6 +18,7 @@ def up remove_column :campaigns, :expiration remove_column :campaigns, :end_time end + def down add_column :events, :end_time, :time add_column :events, :start_time, :time @@ -25,7 +26,7 @@ def down add_column :campaigns, :expiration, :date add_column :campaigns, :end_time, :time Qx.update(:events) - .set(%Q(end_time = end_datetime::time, start_time = start_datetime::time, "date" = start_datetime::date)) + .set(%(end_time = end_datetime::time, start_time = start_datetime::time, "date" = start_datetime::date)) .where("created_at > '2012-01-01'") .execute Qx.update(:campaigns) diff --git a/db/migrate/20170322203228_add_donation_campaign_id_index.rb b/db/migrate/20170322203228_add_donation_campaign_id_index.rb index 8fa5a6d8a..b4c24abe0 100644 --- a/db/migrate/20170322203228_add_donation_campaign_id_index.rb +++ b/db/migrate/20170322203228_add_donation_campaign_id_index.rb @@ -1,13 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class AddDonationCampaignIdIndex < ActiveRecord::Migration def up - Qx.execute(%Q( + Qx.execute(%( CREATE INDEX IF NOT EXISTS donations_campaign_id ON donations (campaign_id); CREATE INDEX IF NOT EXISTS donations_event_id ON donations (event_id); )) end + def down - Qx.execute(%Q( + Qx.execute(%( DROP INDEX IF EXISTS donations_campaign_id; DROP INDEX IF EXISTS donations_event_id; )) diff --git a/db/migrate/20170805180556_add_the_tag_joins_backup_table.rb b/db/migrate/20170805180556_add_the_tag_joins_backup_table.rb index a77dfa347..1a83c4a60 100644 --- a/db/migrate/20170805180556_add_the_tag_joins_backup_table.rb +++ b/db/migrate/20170805180556_add_the_tag_joins_backup_table.rb @@ -2,11 +2,11 @@ class AddTheTagJoinsBackupTable < ActiveRecord::Migration def up create_table :tag_joins_backup do |t| - t.integer 'tag_master_id' - t.integer 'supporter_id' - t.datetime 'created_at' - t.datetime 'updated_at' - t.text 'metadata' + t.integer "tag_master_id" + t.integer "supporter_id" + t.datetime "created_at" + t.datetime "updated_at" + t.text "metadata" end end diff --git a/db/migrate/20170805180557_add_index_for_tag_joins_and_add_constraint.rb b/db/migrate/20170805180557_add_index_for_tag_joins_and_add_constraint.rb index fb22e96c3..26d858f48 100644 --- a/db/migrate/20170805180557_add_index_for_tag_joins_and_add_constraint.rb +++ b/db/migrate/20170805180557_add_index_for_tag_joins_and_add_constraint.rb @@ -3,11 +3,11 @@ class AddIndexForTagJoinsAndAddConstraint < ActiveRecord::Migration def up ids = DeleteTagJoins.find_multiple_tag_joins DeleteTagJoins.copy_and_delete(ids) - add_index :tag_joins, [:tag_master_id, :supporter_id], :unique => true, :name => 'tag_join_supporter_unique_idx' + add_index :tag_joins, [:tag_master_id, :supporter_id], unique: true, name: "tag_join_supporter_unique_idx" end def down - remove_index(:tag_joins, :name => 'tag_join_supporter_unique_idx') + remove_index(:tag_joins, name: "tag_join_supporter_unique_idx") DeleteTagJoins.revert end end diff --git a/db/migrate/20170805180558_add_custom_field_joins_backup_table.rb b/db/migrate/20170805180558_add_custom_field_joins_backup_table.rb index db8187a9b..e1a36b82a 100644 --- a/db/migrate/20170805180558_add_custom_field_joins_backup_table.rb +++ b/db/migrate/20170805180558_add_custom_field_joins_backup_table.rb @@ -2,10 +2,10 @@ class AddCustomFieldJoinsBackupTable < ActiveRecord::Migration def change create_table :custom_field_joins_backup do |t| - t.integer 'custom_field_master_id' - t.integer 'supporter_id' - t.text 'metadata' - t.text 'value' + t.integer "custom_field_master_id" + t.integer "supporter_id" + t.text "metadata" + t.text "value" t.timestamps end end diff --git a/db/migrate/20170805180559_add_index_for_custom_field_join_and_supporters.rb b/db/migrate/20170805180559_add_index_for_custom_field_join_and_supporters.rb index 7da226d63..02629bb87 100644 --- a/db/migrate/20170805180559_add_index_for_custom_field_join_and_supporters.rb +++ b/db/migrate/20170805180559_add_index_for_custom_field_join_and_supporters.rb @@ -3,11 +3,11 @@ class AddIndexForCustomFieldJoinAndSupporters < ActiveRecord::Migration def up ids = DeleteCustomFieldJoins.find_multiple_custom_field_joins DeleteCustomFieldJoins.copy_and_delete(ids) - add_index :custom_field_joins, [:custom_field_master_id, :supporter_id], :unique => true, :name => 'custom_field_join_supporter_unique_idx' + add_index :custom_field_joins, [:custom_field_master_id, :supporter_id], unique: true, name: "custom_field_join_supporter_unique_idx" end def down - remove_index(:custom_field_joins, :name => 'custom_field_join_supporter_unique_idx') + remove_index(:custom_field_joins, name: "custom_field_join_supporter_unique_idx") DeleteCustomFieldJoins.revert end end diff --git a/db/migrate/20170808180559_add_inactive_to_card.rb b/db/migrate/20170808180559_add_inactive_to_card.rb index 6b18d4cf8..69f9e8fb9 100644 --- a/db/migrate/20170808180559_add_inactive_to_card.rb +++ b/db/migrate/20170808180559_add_inactive_to_card.rb @@ -3,11 +3,12 @@ class AddInactiveToCard < ActiveRecord::Migration class Card < ActiveRecord::Base attr_accessible :inactive end + def change add_column :cards, :inactive, :boolean add_index :cards, [:id, :holder_type, :holder_id, :inactive] # add index for getting active_card Card.reset_column_information - Card.update_all(:inactive => false) + Card.update_all(inactive: false) end end diff --git a/db/migrate/20171026102139_add_direct_debit_detail.rb b/db/migrate/20171026102139_add_direct_debit_detail.rb index 634dd7ee3..ecda400c2 100644 --- a/db/migrate/20171026102139_add_direct_debit_detail.rb +++ b/db/migrate/20171026102139_add_direct_debit_detail.rb @@ -11,9 +11,9 @@ def change end add_column :donations, - :direct_debit_detail_id, - :integer, - index: true, - references: :direct_debit_details + :direct_debit_detail_id, + :integer, + references: :direct_debit_details + add_index :donations, :direct_debit_detail_id end end diff --git a/db/migrate/20180202181929_remove_unused_metadata.rb b/db/migrate/20180202181929_remove_unused_metadata.rb index 182f0642d..70c458efb 100644 --- a/db/migrate/20180202181929_remove_unused_metadata.rb +++ b/db/migrate/20180202181929_remove_unused_metadata.rb @@ -1,48 +1,46 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class RemoveUnusedMetadata < ActiveRecord::Migration - TABLES = [ - :campaign_gift_options, - :campaign_gifts, - :campaigns, - :cards, - :charges, - :custom_field_masters, - :custom_field_joins, - :disputes, - :donations, - :events, - :imports, - :nonprofits, - :offsite_payments, - :payments, - :payment_payouts, - :payouts, - :profiles, - :recurring_donations, - :refunds, - :roles, - :supporter_emails, - :supporter_notes, - :supporters, - :tag_joins, - :tag_masters, - :ticket_levels, - :tickets, - :users + :campaign_gift_options, + :campaign_gifts, + :campaigns, + :cards, + :charges, + :custom_field_masters, + :custom_field_joins, + :disputes, + :donations, + :events, + :imports, + :nonprofits, + :offsite_payments, + :payments, + :payment_payouts, + :payouts, + :profiles, + :recurring_donations, + :refunds, + :roles, + :supporter_emails, + :supporter_notes, + :supporters, + :tag_joins, + :tag_masters, + :ticket_levels, + :tickets, + :users ] - FIELDS= [:id, :metadata ] + FIELDS = [:id, :metadata] def up - TABLES.each{|table| + TABLES.each { |table| remove_column table, :metadata } end def down - TABLES.each{|table| + TABLES.each { |table| add_column table, :metadata, :text } - end end diff --git a/db/migrate/20180213191755_remove_recurring_donation_event_id.rb b/db/migrate/20180213191755_remove_recurring_donation_event_id.rb index f1c207a3b..1bfafe8eb 100644 --- a/db/migrate/20180213191755_remove_recurring_donation_event_id.rb +++ b/db/migrate/20180213191755_remove_recurring_donation_event_id.rb @@ -5,5 +5,4 @@ def change t.remove :event_id end end - end diff --git a/db/migrate/20180214124311_create_source_tokens.rb b/db/migrate/20180214124311_create_source_tokens.rb index f4d0fae32..931d1878f 100644 --- a/db/migrate/20180214124311_create_source_tokens.rb +++ b/db/migrate/20180214124311_create_source_tokens.rb @@ -2,18 +2,17 @@ class CreateSourceTokens < ActiveRecord::Migration def change create_table :source_tokens, id: false do |t| - t.column :token, 'uuid', primary_key: true, null:false + t.column :token, "uuid", primary_key: true, null: false t.datetime :expiration - t.references :tokenizable, :polymorphic => true + t.references :tokenizable, polymorphic: true t.references :event t.integer :max_uses, default: 1 t.integer :total_uses, default: 0 t.timestamps end - add_index :source_tokens, :token, :unique => true + add_index :source_tokens, :token, unique: true add_index :source_tokens, :expiration add_index :source_tokens, [:tokenizable_id, :tokenizable_type] - end end diff --git a/db/migrate/20180215124311_add_card_token_to_ticket.rb b/db/migrate/20180215124311_add_card_token_to_ticket.rb index 6a86b920c..11de24522 100644 --- a/db/migrate/20180215124311_add_card_token_to_ticket.rb +++ b/db/migrate/20180215124311_add_card_token_to_ticket.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class AddCardTokenToTicket < ActiveRecord::Migration def up - add_column :tickets, :source_token_id, 'uuid' + add_column :tickets, :source_token_id, "uuid" end def down diff --git a/db/migrate/20180216064311_add_indexes_to_supporter_notes.rb b/db/migrate/20180216064311_add_indexes_to_supporter_notes.rb index cc7cb1c18..60dfeedc3 100644 --- a/db/migrate/20180216064311_add_indexes_to_supporter_notes.rb +++ b/db/migrate/20180216064311_add_indexes_to_supporter_notes.rb @@ -1,5 +1,5 @@ class AddIndexesToSupporterNotes < ActiveRecord::Migration def change - add_index :supporter_notes, :supporter_id, :order => {:supporter_id => :asc} + add_index :supporter_notes, :supporter_id, order: {supporter_id: :asc} end end diff --git a/db/migrate/20180713213748_add_charge_id_indexes.rb b/db/migrate/20180713213748_add_charge_id_indexes.rb index 52d50a5e8..d70be001d 100644 --- a/db/migrate/20180713213748_add_charge_id_indexes.rb +++ b/db/migrate/20180713213748_add_charge_id_indexes.rb @@ -2,5 +2,4 @@ class AddChargeIdIndexes < ActiveRecord::Migration def change add_index :refunds, :charge_id end - end diff --git a/db/migrate/20181002160627_correct_dedications.rb b/db/migrate/20181002160627_correct_dedications.rb index 40657773d..a22aa1b8e 100644 --- a/db/migrate/20181002160627_correct_dedications.rb +++ b/db/migrate/20181002160627_correct_dedications.rb @@ -1,19 +1,19 @@ class CorrectDedications < ActiveRecord::Migration def up - execute <<-SQL - create or replace function is_valid_json(p_json text) - returns boolean -as -$$ -begin - return (p_json::json is not null); -exception - when others then - return false; -end; -$$ -language plpgsql -immutable; + execute <<~SQL + create or replace function is_valid_json(p_json text) + returns boolean + as + $$ + begin + return (p_json::json is not null); + exception + when others then + return false; + end; + $$ + language plpgsql + immutable; SQL dedications = MaintainDedications.retrieve_non_json_dedications @@ -27,4 +27,3 @@ def up def down end end - diff --git a/db/migrate/20181003212559_correct_dedication_contacts.rb b/db/migrate/20181003212559_correct_dedication_contacts.rb index 9631d9ba6..c970c8994 100644 --- a/db/migrate/20181003212559_correct_dedication_contacts.rb +++ b/db/migrate/20181003212559_correct_dedication_contacts.rb @@ -1,27 +1,27 @@ class CorrectDedicationContacts < ActiveRecord::Migration def up - json_dedications = Qx.select('id', 'dedication').from(:donations) - .where("dedication IS NOT NULL AND dedication != ''") - .and_where("is_valid_json(dedication)").ex - parsed_dedications = json_dedications.map{|i| {id: i['id'], dedication: JSON.parse(i['dedication'])}} - with_contact_to_correct = parsed_dedications.select {|i| !i[:dedication]['contact'].blank? && i[:dedication]['contact'].is_a?(String)} - really_icky_dedications, easy_to_split_strings = with_contact_to_correct.partition{|i| i[:dedication]['contact'].split(" - ").count > 3} + json_dedications = Qx.select("id", "dedication").from(:donations) + .where("dedication IS NOT NULL AND dedication != ''") + .and_where("is_valid_json(dedication)").ex + parsed_dedications = json_dedications.map { |i| {id: i["id"], dedication: JSON.parse(i["dedication"])} } + with_contact_to_correct = parsed_dedications.select { |i| !i[:dedication]["contact"].blank? && i[:dedication]["contact"].is_a?(String) } + really_icky_dedications, easy_to_split_strings = with_contact_to_correct.partition { |i| i[:dedication]["contact"].split(" - ").count > 3 } - easy_to_split_strings.map do |i| - split_contact = i[:dedication]['contact'].split(' - ') - i[:dedication]['contact'] = { - email: split_contact[0], - phone:split_contact[1], - address: split_contact[2], - } - puts i - i - end.each_with_index do |i, index| - unless (i[:id]) - raise Error("Item at index #{index} is invalid. Object:#{i}") - end - Qx.update(:donations).where("id = $id", id:i[:id]).set(dedication: JSON.generate(i[:dedication])).ex - end + easy_to_split_strings.map do |i| + split_contact = i[:dedication]["contact"].split(" - ") + i[:dedication]["contact"] = { + email: split_contact[0], + phone: split_contact[1], + address: split_contact[2] + } + puts i + i + end.each_with_index do |i, index| + unless i[:id] + raise Error("Item at index #{index} is invalid. Object:#{i}") + end + Qx.update(:donations).where("id = $id", id: i[:id]).set(dedication: JSON.generate(i[:dedication])).ex + end puts "Corrected #{easy_to_split_strings.count} records." @@ -34,19 +34,19 @@ def up end def down - json_dedications = Qx.select('id', 'dedication').from(:donations) - .where("dedication IS NOT NULL AND dedication != ''") - .and_where("is_valid_json(dedication)").ex + json_dedications = Qx.select("id", "dedication").from(:donations) + .where("dedication IS NOT NULL AND dedication != ''") + .and_where("is_valid_json(dedication)").ex - parsed_dedications = json_dedications.map{|i| {'id' => i['id'], 'dedication' => JSON.parse(i['dedication'])}} + parsed_dedications = json_dedications.map { |i| {"id" => i["id"], "dedication" => JSON.parse(i["dedication"])} } - with_contact_to_correct = parsed_dedications.select {|i| i['dedication']['contact'].is_a?(Hash)} + with_contact_to_correct = parsed_dedications.select { |i| i["dedication"]["contact"].is_a?(Hash) } puts "#{with_contact_to_correct.count} to revert" with_contact_to_correct.each do |i| - contact_string = "#{i['dedication']['contact']['email']} - #{i['dedication']['contact']['phone']} - #{i['dedication']['contact']['address']}" - i['dedication']['contact'] = contact_string - Qx.update(:donations).where("id = $id", id:i['id']).set(dedication: JSON.generate(i['dedication'])).ex + contact_string = "#{i["dedication"]["contact"]["email"]} - #{i["dedication"]["contact"]["phone"]} - #{i["dedication"]["contact"]["address"]}" + i["dedication"]["contact"] = contact_string + Qx.update(:donations).where("id = $id", id: i["id"]).set(dedication: JSON.generate(i["dedication"])).ex end end end diff --git a/db/migrate/20191122173716_create_misc_campaign_infos.rb b/db/migrate/20191122173716_create_misc_campaign_infos.rb index 2101ad12c..a053f8182 100644 --- a/db/migrate/20191122173716_create_misc_campaign_infos.rb +++ b/db/migrate/20191122173716_create_misc_campaign_infos.rb @@ -1,11 +1,9 @@ class CreateMiscCampaignInfos < ActiveRecord::Migration def change create_table :misc_campaign_infos do |t| - t.timestamps t.references :campaign t.boolean :manual_cover_fees - end add_index :misc_campaign_infos, :campaign_id diff --git a/db/migrate/20200130222233_create_nonprofit_verification_process_statuses.rb b/db/migrate/20200130222233_create_nonprofit_verification_process_statuses.rb index 63501d8d8..6b5f17c50 100644 --- a/db/migrate/20200130222233_create_nonprofit_verification_process_statuses.rb +++ b/db/migrate/20200130222233_create_nonprofit_verification_process_statuses.rb @@ -1,12 +1,12 @@ class CreateNonprofitVerificationProcessStatuses < ActiveRecord::Migration def change create_table :nonprofit_verification_process_statuses do |t| - t.string :stripe_account_id, null:false + t.string :stripe_account_id, null: false t.datetime :started_at t.string :email_to_send_guid t.timestamps end - add_index :nonprofit_verification_process_statuses, :stripe_account_id, unique: true, name: 'index_nonprofit_verification_to_stripe' + add_index :nonprofit_verification_process_statuses, :stripe_account_id, unique: true, name: "index_nonprofit_verification_to_stripe" end end diff --git a/db/migrate/20200408192744_clarify_deleted_columns.rb b/db/migrate/20200408192744_clarify_deleted_columns.rb index 11f457065..0cdcea2d7 100644 --- a/db/migrate/20200408192744_clarify_deleted_columns.rb +++ b/db/migrate/20200408192744_clarify_deleted_columns.rb @@ -1,65 +1,55 @@ class ClarifyDeletedColumns < ActiveRecord::Migration def up - TagMaster.where('deleted IS NULL').update_all(deleted:false) + TagMaster.where("deleted IS NULL").update_all(deleted: false) change_column(:tag_masters, :deleted, :boolean, default: false) - - TicketLevel.where('deleted IS NULL').update_all(deleted: false) + + TicketLevel.where("deleted IS NULL").update_all(deleted: false) change_column(:ticket_levels, :deleted, :boolean, default: false) - Ticket.where('deleted IS NULL').update_all(deleted: false) + Ticket.where("deleted IS NULL").update_all(deleted: false) change_column(:tickets, :deleted, :boolean, default: false) - BankAccount.where('deleted IS NULL').update_all(deleted: false) + BankAccount.where("deleted IS NULL").update_all(deleted: false) change_column(:bank_accounts, :deleted, :boolean, default: false) - Campaign.where('deleted IS NULL').update_all(deleted: false) + Campaign.where("deleted IS NULL").update_all(deleted: false) change_column(:campaigns, :deleted, :boolean, default: false) - Card.where('deleted IS NULL').update_all(deleted: false) + Card.where("deleted IS NULL").update_all(deleted: false) change_column(:cards, :deleted, :boolean, default: false) - CustomFieldMaster.where('deleted IS NULL').update_all(deleted:false) + CustomFieldMaster.where("deleted IS NULL").update_all(deleted: false) change_column(:custom_field_masters, :deleted, :boolean, default: false) - Event.where('deleted IS NULL').update_all(deleted:false) + Event.where("deleted IS NULL").update_all(deleted: false) change_column(:events, :deleted, :boolean, default: false) - SupporterNote.where('deleted IS NULL').update_all(deleted:false) + SupporterNote.where("deleted IS NULL").update_all(deleted: false) change_column(:supporter_notes, :deleted, :boolean, default: false) - Supporter.where('deleted IS NULL').update_all(deleted:false) + Supporter.where("deleted IS NULL").update_all(deleted: false) change_column(:supporters, :deleted, :boolean, default: false) end def down - change_column(:tag_masters, :deleted, :boolean) - change_column(:ticket_levels, :deleted, :boolean) - change_column(:tickets, :deleted, :boolean) - change_column(:bank_accounts, :deleted, :boolean) - change_column(:campaigns, :deleted, :boolean) - change_column(:cards, :deleted, :boolean) - change_column(:custom_field_masters, :deleted, :boolean) - change_column(:events, :deleted, :boolean) - change_column(:supporter_notes, :deleted, :boolean) - change_column(:supporters, :deleted, :boolean) end end diff --git a/db/migrate/20200409191419_add_indexes_to_events.rb b/db/migrate/20200409191419_add_indexes_to_events.rb index ced2d1204..fa2377a19 100644 --- a/db/migrate/20200409191419_add_indexes_to_events.rb +++ b/db/migrate/20200409191419_add_indexes_to_events.rb @@ -2,12 +2,12 @@ class AddIndexesToEvents < ActiveRecord::Migration def up add_index :events, :nonprofit_id add_index :events, [:nonprofit_id, :deleted, :published] - add_index :events, [:nonprofit_id, :deleted, :published, :end_datetime], name: 'events_nonprofit_id_not_deleted_and_published_endtime' + add_index :events, [:nonprofit_id, :deleted, :published, :end_datetime], name: "events_nonprofit_id_not_deleted_and_published_endtime" end def down remove_index :events, :nonprofit_id remove_index :events, [:nonprofit_id, :deleted, :published] - remove_index :events, name: 'events_nonprofit_id_not_deleted_and_published_endtime' + remove_index :events, name: "events_nonprofit_id_not_deleted_and_published_endtime" end end diff --git a/db/migrate/20200415214804_remove_verification_status_on_nonprofit.rb b/db/migrate/20200415214804_remove_verification_status_on_nonprofit.rb index 3ceefe796..66613d75c 100644 --- a/db/migrate/20200415214804_remove_verification_status_on_nonprofit.rb +++ b/db/migrate/20200415214804_remove_verification_status_on_nonprofit.rb @@ -16,6 +16,5 @@ def down SQL drop_table :nonprofit_verification_backups - end end diff --git a/db/migrate/20200415220722_remove_supporter_search_vectors.rb b/db/migrate/20200415220722_remove_supporter_search_vectors.rb index 92f26ba7d..fa14e9dca 100644 --- a/db/migrate/20200415220722_remove_supporter_search_vectors.rb +++ b/db/migrate/20200415220722_remove_supporter_search_vectors.rb @@ -14,41 +14,41 @@ def up def down add_column :supporters, :search_vectors, "tsvector" - execute <<-SQL - CREATE FUNCTION public.update_supporter_assoc_search_vectors() RETURNS trigger - LANGUAGE plpgsql - AS $$ BEGIN - IF pg_trigger_depth() <> 1 THEN RETURN new; END IF; - UPDATE supporters - SET search_vectors=to_tsvector('english', data.search_blob) - FROM ( -SELECT supporters.id, concat_ws(' ' - , custom_field_joins.value - , supporters.name - , supporters.organization - , supporters.id - , supporters.email - , supporters.city - , supporters.state_code - , donations.designation - , donations.dedication - , payments.kind - , payments.towards - ) AS search_blob -FROM supporters -LEFT OUTER JOIN payments - ON payments.supporter_id=supporters.id -LEFT OUTER JOIN donations - ON donations.supporter_id=supporters.id -LEFT OUTER JOIN ( -SELECT string_agg(value::text, ' ') AS value, supporter_id -FROM custom_field_joins -GROUP BY supporter_id) AS custom_field_joins - ON custom_field_joins.supporter_id=supporters.id -WHERE (supporters.id=NEW.supporter_id)) AS data - WHERE data.id=supporters.id; - RETURN new; - END $$; + execute <<~SQL + CREATE FUNCTION public.update_supporter_assoc_search_vectors() RETURNS trigger + LANGUAGE plpgsql + AS $$ BEGIN + IF pg_trigger_depth() <> 1 THEN RETURN new; END IF; + UPDATE supporters + SET search_vectors=to_tsvector('english', data.search_blob) + FROM ( + SELECT supporters.id, concat_ws(' ' + , custom_field_joins.value + , supporters.name + , supporters.organization + , supporters.id + , supporters.email + , supporters.city + , supporters.state_code + , donations.designation + , donations.dedication + , payments.kind + , payments.towards + ) AS search_blob + FROM supporters + LEFT OUTER JOIN payments + ON payments.supporter_id=supporters.id + LEFT OUTER JOIN donations + ON donations.supporter_id=supporters.id + LEFT OUTER JOIN ( + SELECT string_agg(value::text, ' ') AS value, supporter_id + FROM custom_field_joins + GROUP BY supporter_id) AS custom_field_joins + ON custom_field_joins.supporter_id=supporters.id + WHERE (supporters.id=NEW.supporter_id)) AS data + WHERE data.id=supporters.id; + RETURN new; + END $$; SQL execute <<-SQL diff --git a/db/migrate/20200805214543_create_dispute_transactions.rb b/db/migrate/20200805214543_create_dispute_transactions.rb index 616aa7139..8dd5d0cad 100644 --- a/db/migrate/20200805214543_create_dispute_transactions.rb +++ b/db/migrate/20200805214543_create_dispute_transactions.rb @@ -15,8 +15,8 @@ def up add_index :dispute_transactions, :payment_id Dispute.all.each do |d| - d.dispute_transactions.create(gross_amount: d.gross_amount * -1, disbursed: d.status == "lost_and_paid", payment: Payment.find(d.payment_id), date: d.started_at) if d.status == "lost" || d.status == 'lost_and_paid' - if (d.status == "lost_and_paid") + d.dispute_transactions.create(gross_amount: d.gross_amount * -1, disbursed: d.status == "lost_and_paid", payment: Payment.find(d.payment_id), date: d.started_at) if d.status == "lost" || d.status == "lost_and_paid" + if d.status == "lost_and_paid" d.status = :lost d.save! end @@ -31,7 +31,7 @@ def down add_index :disputes, :payment_id Dispute.all.each do |d| - if (d.dispute_transactions&.first&.disbursed && d.status == "lost") + if d.dispute_transactions&.first&.disbursed && d.status == "lost" d.status = :lost_and_paid end d.save! diff --git a/db/migrate/20200819200849_add_evidence_due_date_and_started_at.rb b/db/migrate/20200819200849_add_evidence_due_date_and_started_at.rb index b9ba93bea..2f5239983 100644 --- a/db/migrate/20200819200849_add_evidence_due_date_and_started_at.rb +++ b/db/migrate/20200819200849_add_evidence_due_date_and_started_at.rb @@ -2,7 +2,7 @@ class AddEvidenceDueDateAndStartedAt < ActiveRecord::Migration def change add_column :stripe_disputes, :evidence_due_date, :datetime add_column :stripe_disputes, :started_at, :datetime - StripeDispute.all.each do |s| + StripeDispute.all.each do |s| s.object = s.object s.save! end diff --git a/db/migrate/20200928205836_add_full_contact_indexes.rb b/db/migrate/20200928205836_add_full_contact_indexes.rb index 4feac671e..9c20ddc53 100644 --- a/db/migrate/20200928205836_add_full_contact_indexes.rb +++ b/db/migrate/20200928205836_add_full_contact_indexes.rb @@ -1,6 +1,6 @@ class AddFullContactIndexes < ActiveRecord::Migration def change - add_index :full_contact_photos, [:full_contact_info_id, :is_primary], name: 'index_full_context_photo_info_primary' + add_index :full_contact_photos, [:full_contact_info_id, :is_primary], name: "index_full_context_photo_info_primary" add_index :full_contact_orgs, :full_contact_info_id add_index :full_contact_topics, :full_contact_info_id add_index :full_contact_social_profiles, :full_contact_info_id diff --git a/db/migrate/20210122184714_create_transactions.rb b/db/migrate/20210122184714_create_transactions.rb index 71119d906..ff8f951eb 100644 --- a/db/migrate/20210122184714_create_transactions.rb +++ b/db/migrate/20210122184714_create_transactions.rb @@ -3,8 +3,8 @@ class CreateTransactions < ActiveRecord::Migration def change create_table :transactions do |t| - t.references :supporter, index:true - t.string :houid, null: false, index:{unique:true} + t.references :supporter, index: true + t.string :houid, null: false, index: {unique: true} t.integer :amount t.datetime :created, index: {order: :desc} t.timestamps diff --git a/db/migrate/20210416141243_add_full_text_search_to_donations.rb b/db/migrate/20210416141243_add_full_text_search_to_donations.rb index 578875987..2e85f7f3d 100644 --- a/db/migrate/20210416141243_add_full_text_search_to_donations.rb +++ b/db/migrate/20210416141243_add_full_text_search_to_donations.rb @@ -2,7 +2,7 @@ class AddFullTextSearchToDonations < ActiveRecord::Migration def up add_column :donations, :fts, :tsvector - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) UPDATE donations SET fts = (to_tsvector('english', coalesce(comment, ''))); CREATE FUNCTION update_fts_on_donations() RETURNS TRIGGER AS $$ @@ -14,14 +14,14 @@ def up CREATE TRIGGER update_donations_fts BEFORE INSERT OR UPDATE ON donations FOR EACH ROW EXECUTE PROCEDURE update_fts_on_donations(); - eosql + EOSQL end def down - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) DROP FUNCTION update_fts_on_donations () CASCADE; DROP TRIGGER IF EXISTS update_donations_fts ON donations; - eosql + EOSQL remove_column :donations, :fts end end diff --git a/db/migrate/20210416143448_add_full_text_search_to_supporters.rb b/db/migrate/20210416143448_add_full_text_search_to_supporters.rb index 3f2b15fe7..db8a20ead 100644 --- a/db/migrate/20210416143448_add_full_text_search_to_supporters.rb +++ b/db/migrate/20210416143448_add_full_text_search_to_supporters.rb @@ -2,7 +2,7 @@ class AddFullTextSearchToSupporters < ActiveRecord::Migration def up add_column :supporters, :fts, :tsvector - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) UPDATE supporters SET fts = (to_tsvector('english', coalesce(name, '') || ' ' || coalesce(email, ''))); CREATE FUNCTION update_fts_on_supporters() RETURNS TRIGGER AS $$ @@ -14,14 +14,14 @@ def up CREATE TRIGGER update_supporters_fts BEFORE INSERT OR UPDATE ON supporters FOR EACH ROW EXECUTE PROCEDURE update_fts_on_supporters(); - eosql + EOSQL end def down - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) DROP FUNCTION update_fts_on_supporters () CASCADE; DROP TRIGGER IF EXISTS update_supporters_fts ON supporters; - eosql + EOSQL remove_column :supporters, :fts end end diff --git a/db/migrate/20210524185334_add_donations_fts_index.rb b/db/migrate/20210524185334_add_donations_fts_index.rb index 13e4130a0..acc39fab3 100644 --- a/db/migrate/20210524185334_add_donations_fts_index.rb +++ b/db/migrate/20210524185334_add_donations_fts_index.rb @@ -1,14 +1,14 @@ class AddDonationsFtsIndex < ActiveRecord::Migration disable_ddl_transaction! def up - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) CREATE INDEX CONCURRENTLY donations_fts_idx ON donations USING gin(fts); - eosql + EOSQL end def down - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) DROP INDEX IF EXISTS donations_fts_idx; - eosql + EOSQL end end diff --git a/db/migrate/20210524185342_add_supporters_fts_index.rb b/db/migrate/20210524185342_add_supporters_fts_index.rb index 7bd7d6e4a..b2f1ffa62 100644 --- a/db/migrate/20210524185342_add_supporters_fts_index.rb +++ b/db/migrate/20210524185342_add_supporters_fts_index.rb @@ -1,14 +1,14 @@ class AddSupportersFtsIndex < ActiveRecord::Migration disable_ddl_transaction! def up - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) CREATE INDEX CONCURRENTLY supporters_fts_idx ON supporters USING gin(fts); - eosql + EOSQL end def down - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) DROP INDEX IF EXISTS supporters_fts_idx; - eosql + EOSQL end end diff --git a/db/migrate/20210712192642_add_check_number_index_to_offsite_payments.rb b/db/migrate/20210712192642_add_check_number_index_to_offsite_payments.rb index 8e2987403..017f7c739 100644 --- a/db/migrate/20210712192642_add_check_number_index_to_offsite_payments.rb +++ b/db/migrate/20210712192642_add_check_number_index_to_offsite_payments.rb @@ -1,5 +1,4 @@ class AddCheckNumberIndexToOffsitePayments < ActiveRecord::Migration - def change add_index :offsite_payments, :check_number end diff --git a/db/migrate/20210714215241_create_fee_eras_structures_and_cover_detail_bases.rb b/db/migrate/20210714215241_create_fee_eras_structures_and_cover_detail_bases.rb index 884638307..61dda03de 100644 --- a/db/migrate/20210714215241_create_fee_eras_structures_and_cover_detail_bases.rb +++ b/db/migrate/20210714215241_create_fee_eras_structures_and_cover_detail_bases.rb @@ -1,14 +1,13 @@ class CreateFeeErasStructuresAndCoverDetailBases < ActiveRecord::Migration - def create_record(sql_command) - execute(sql_command).getvalue(0,0).to_i + execute(sql_command).getvalue(0, 0).to_i end def get_fee_era_id(where_clause) execute(<<-SQL SELECT id from fee_eras WHERE #{where_clause}; SQL - ).getvalue(0,0).to_i + ).getvalue(0, 0).to_i end def delete_fee_era_id(where_clause) @@ -27,7 +26,6 @@ def delete_fee_era_id(where_clause) SQL end - def change create_table :fee_eras do |t| t.datetime :start_time @@ -53,64 +51,62 @@ def change create_table :fee_coverage_detail_bases do |t| t.integer :flat_fee t.decimal :percentage_fee - t.boolean :dont_consider_billing_plan, null:false, default: false + t.boolean :dont_consider_billing_plan, null: false, default: false t.references :fee_era, required: true, foreign_key: true t.timestamps null: false end - reversible do |dir| - dir.up do oldest_fee_era = create_record <<-SQL INSERT INTO fee_eras (end_time, refund_stripe_fee, created_at, updated_at) VALUES (to_timestamp(1601510400), true, now(), now()) RETURNING id; SQL - + execute <<-SQL INSERT INTO fee_structures (fee_era_id, flat_fee, stripe_fee, created_at, updated_at) VALUES (#{oldest_fee_era}, 30, 0.022, now(), now()) SQL - + execute <<-SQL INSERT INTO fee_coverage_detail_bases (fee_era_id, flat_fee, percentage_fee, created_at, updated_at) VALUES (#{oldest_fee_era}, 30, 0.022, now(), now()) SQL - + middle_fee_era = create_record <<-SQL INSERT INTO fee_eras (start_time, end_time, local_country, international_surcharge_fee, created_at, updated_at) VALUES (to_timestamp(1601510400), to_timestamp(1627696800), 'US', 0.01, now(), now()) RETURNING id; SQL - + execute <<-SQL INSERT INTO fee_structures (fee_era_id, flat_fee, stripe_fee, created_at, updated_at) VALUES (#{middle_fee_era}, 30, 0.022, now(), now()) SQL - + execute <<-SQL INSERT INTO fee_structures (fee_era_id, flat_fee, stripe_fee, created_at, updated_at, brand) VALUES (#{middle_fee_era}, 0, 0.035, now(), now(), 'American Express') SQL - + execute <<-SQL INSERT INTO fee_coverage_detail_bases (fee_era_id, flat_fee, percentage_fee, created_at, updated_at, dont_consider_billing_plan) VALUES (#{middle_fee_era}, 0, 0.05, now(), now(), true) SQL - + latest_fee_era = create_record <<-SQL INSERT INTO fee_eras (start_time, local_country, international_surcharge_fee,created_at, updated_at) VALUES (to_timestamp(1627696800), 'US', 0.01, now(), now()) RETURNING id; SQL - + execute <<-SQL INSERT INTO fee_structures (fee_era_id, flat_fee, stripe_fee, created_at, updated_at) VALUES (#{latest_fee_era}, 25, 0.02, now(), now()) SQL - + execute <<-SQL INSERT INTO fee_coverage_detail_bases (fee_era_id, flat_fee, percentage_fee, created_at, updated_at) VALUES (#{latest_fee_era}, 25, 0.02, now(), now()) diff --git a/db/migrate/20210715191012_add_organization_to_fts_index.rb b/db/migrate/20210715191012_add_organization_to_fts_index.rb index 5ff49ce8b..ca9d33afc 100644 --- a/db/migrate/20210715191012_add_organization_to_fts_index.rb +++ b/db/migrate/20210715191012_add_organization_to_fts_index.rb @@ -1,15 +1,14 @@ class AddOrganizationToFtsIndex < ActiveRecord::Migration - def drop_fts_triggers - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) DROP FUNCTION update_fts_on_supporters () CASCADE; DROP TRIGGER IF EXISTS update_supporters_fts ON supporters; - eosql + EOSQL end def up drop_fts_triggers - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) CREATE FUNCTION update_fts_on_supporters() RETURNS TRIGGER AS $$ BEGIN @@ -20,14 +19,12 @@ def up CREATE TRIGGER update_supporters_fts BEFORE INSERT OR UPDATE ON supporters FOR EACH ROW EXECUTE PROCEDURE update_fts_on_supporters(); - eosql - + EOSQL end def down - drop_fts_triggers - execute(<<-'eosql'.strip) + execute(<<-EOSQL.strip) CREATE FUNCTION update_fts_on_supporters() RETURNS TRIGGER AS $$ BEGIN @@ -38,6 +35,6 @@ def down CREATE TRIGGER update_supporters_fts BEFORE INSERT OR UPDATE ON supporters FOR EACH ROW EXECUTE PROCEDURE update_fts_on_supporters(); - eosql + EOSQL end end diff --git a/db/migrate/20210721175103_change_billing_plan_percentage_fee_to_decimal.rb b/db/migrate/20210721175103_change_billing_plan_percentage_fee_to_decimal.rb index a1b9504f8..01c088133 100644 --- a/db/migrate/20210721175103_change_billing_plan_percentage_fee_to_decimal.rb +++ b/db/migrate/20210721175103_change_billing_plan_percentage_fee_to_decimal.rb @@ -1,6 +1,5 @@ class ChangeBillingPlanPercentageFeeToDecimal < ActiveRecord::Migration def change - change_column :billing_plans, :percentage_fee, :decimal, null: false, default: 0 end end diff --git a/db/migrate/20210804203440_add_index_to_phone_on_supporter.rb b/db/migrate/20210804203440_add_index_to_phone_on_supporter.rb index 0e39b61bc..eb7d87f87 100644 --- a/db/migrate/20210804203440_add_index_to_phone_on_supporter.rb +++ b/db/migrate/20210804203440_add_index_to_phone_on_supporter.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class AddIndexToPhoneOnSupporter < ActiveRecord::Migration - def change add_column :supporters, :phone_index, :string reversible do |dir| - dir.up do - execute(<<-'eosql'.strip) + dir.up do + execute(<<-'EOSQL'.strip) CREATE FUNCTION update_phone_index_on_supporters() RETURNS TRIGGER AS $$ BEGIN new.phone_index = (regexp_replace(new.phone, '\D','', 'g')); @@ -15,14 +14,14 @@ def change CREATE TRIGGER update_supporters_phone_index BEFORE INSERT OR UPDATE ON supporters FOR EACH ROW EXECUTE PROCEDURE update_phone_index_on_supporters(); - eosql + EOSQL end - dir.down do - execute(<<-'eosql'.strip) + dir.down do + execute(<<-EOSQL.strip) DROP FUNCTION update_phone_index_on_supporters () CASCADE; DROP TRIGGER IF EXISTS update_supporters_phone_index ON supporters; - eosql + EOSQL end end diff --git a/db/migrate/20211119224854_add_supporter_houid.rb b/db/migrate/20211119224854_add_supporter_houid.rb index 98bebe304..06d3f1811 100644 --- a/db/migrate/20211119224854_add_supporter_houid.rb +++ b/db/migrate/20211119224854_add_supporter_houid.rb @@ -1,5 +1,6 @@ class AddSupporterHouid < ActiveRecord::Migration def change - add_column :supporters, :houid, :string, index: {unique: true} + add_column :supporters, :houid, :string + add_index :supporters, :houid, unique: true end end diff --git a/db/migrate/20211210185111_create_e_tap_imports.rb b/db/migrate/20211210185111_create_e_tap_imports.rb index ada5cbafd..0caab87b6 100644 --- a/db/migrate/20211210185111_create_e_tap_imports.rb +++ b/db/migrate/20211210185111_create_e_tap_imports.rb @@ -6,12 +6,11 @@ def change end create_table :e_tap_import_journal_entries do |t| - t.references :e_tap_import, index:true + t.references :e_tap_import, index: true t.jsonb :row - - # t.index "row ->> 'Account Number'", using: "GIN", name: "by_account_number" - + # t.index "row ->> 'Account Number'", using: "GIN", name: "by_account_number" + t.timestamps null: false end @@ -26,7 +25,7 @@ def change # execute <<-SQL # CREATE INDEX by_account_number_journal_entries on e_tap_import_journal_entries # USING GIN ("row" jsonb_path_ops); - + # SQL # end # dir.down do @@ -37,12 +36,11 @@ def change # end create_table :e_tap_import_contacts do |t| - t.references :e_tap_import, index:true + t.references :e_tap_import, index: true t.jsonb :row - #t.index "row ->> 'Account Number'", using: "GIN", name: "by_account_number" - t.references :supporter, index:true + # t.index "row ->> 'Account Number'", using: "GIN", name: "by_account_number" + t.references :supporter, index: true t.timestamps null: false end end - end diff --git a/db/migrate/20211222175658_add_nonprofit_houid.rb b/db/migrate/20211222175658_add_nonprofit_houid.rb index ff615ff15..f8a88e615 100644 --- a/db/migrate/20211222175658_add_nonprofit_houid.rb +++ b/db/migrate/20211222175658_add_nonprofit_houid.rb @@ -1,5 +1,6 @@ class AddNonprofitHouid < ActiveRecord::Migration def change - add_column :nonprofits, :houid, :string, index: {unique: true} + add_column :nonprofits, :houid, :string + add_index :nonprofits, :houid, unique: true end end diff --git a/db/migrate/20211223202404_add_minimal_trx_tables_to_create_donations.rb b/db/migrate/20211223202404_add_minimal_trx_tables_to_create_donations.rb index b1f423c71..36c680cd9 100644 --- a/db/migrate/20211223202404_add_minimal_trx_tables_to_create_donations.rb +++ b/db/migrate/20211223202404_add_minimal_trx_tables_to_create_donations.rb @@ -1,42 +1,41 @@ class AddMinimalTrxTablesToCreateDonations < ActiveRecord::Migration def change - create_table :transaction_assignments do |t| t.references :transaction, null: false - t.references :assignable, polymorphic: true, index: { unique: true, name: 'idx_trx_assignments_assignable_polymorphic' }, null: false + t.references :assignable, polymorphic: true, index: {unique: true, name: "idx_trx_assignments_assignable_polymorphic"}, null: false end create_table :modern_donations do |t| t.integer :amount t.references :donation, null: false - t.string :houid, null:false, index: {unique:true} + t.string :houid, null: false, index: {unique: true} t.timestamps end create_table :subtransactions do |t| t.references :transaction, null: false - t.references :subtransactable, polymorphic: true, null: false, index: {unique: true, name: 'idx_subtrx_on_subtransactable_polymorphic'} - t.datetime "created", comment: 'the moment that the subtransaction was created. Could be earlier than created_at if the transaction was in the past.' + t.references :subtransactable, polymorphic: true, null: false, index: {unique: true, name: "idx_subtrx_on_subtransactable_polymorphic"} + t.datetime "created", comment: "the moment that the subtransaction was created. Could be earlier than created_at if the transaction was in the past." t.timestamps end create_table "offline_transactions" do |t| t.integer "amount", null: false - t.string :houid, null:false, index: {unique:true} + t.string :houid, null: false, index: {unique: true} t.timestamps end create_table :subtransaction_payments do |t| t.references :subtransaction, null: false - t.references :paymentable, polymorphic: true, null: false, index: {unique: true, name: 'idx_subtrxpayments_on_subtransactable_polymorphic'} - t.datetime "created", comment: 'the moment that the subtransaction_payment was created. Could be earlier than created_at if the transaction was in the past.' + t.references :paymentable, polymorphic: true, null: false, index: {unique: true, name: "idx_subtrxpayments_on_subtransactable_polymorphic"} + t.datetime "created", comment: "the moment that the subtransaction_payment was created. Could be earlier than created_at if the transaction was in the past." t.references :legacy_payment, null: false, index: {unique: true} t.timestamps end create_table :offline_transaction_charges do |t| - t.string :houid, null:false, index: {unique:true} + t.string :houid, null: false, index: {unique: true} t.timestamps end end diff --git a/db/migrate/20220111203102_create_object_events.rb b/db/migrate/20220111203102_create_object_events.rb index aa9fd4569..7d1bce04b 100644 --- a/db/migrate/20220111203102_create_object_events.rb +++ b/db/migrate/20220111203102_create_object_events.rb @@ -1,10 +1,10 @@ class CreateObjectEvents < ActiveRecord::Migration def change create_table :object_events do |t| - t.references :event_entity, {polymorphic: true, index:true} + t.references :event_entity, {polymorphic: true, index: true} t.index :event_entity_type - t.string :event_type, {index:true} - t.string :event_entity_houid, {index:true} + t.string :event_type, {index: true} + t.string :event_entity_houid, {index: true} t.references :nonprofit, {index: true} t.string :houid, {index: true} t.datetime :created diff --git a/db/migrate/20220121194545_create_stripe_charge_payments.rb b/db/migrate/20220121194545_create_stripe_charge_payments.rb index d762a919e..f2cd11731 100644 --- a/db/migrate/20220121194545_create_stripe_charge_payments.rb +++ b/db/migrate/20220121194545_create_stripe_charge_payments.rb @@ -1,8 +1,7 @@ class CreateStripeChargePayments < ActiveRecord::Migration def change - create_table :stripe_transactions do |t| - t.integer :amount, null:false + t.integer :amount, null: false t.string :houid, {index: true, null: false} t.timestamps diff --git a/db/migrate/20220211204841_move_to_fx_functions.rb b/db/migrate/20220211204841_move_to_fx_functions.rb index adfbfa9d5..998980432 100644 --- a/db/migrate/20220211204841_move_to_fx_functions.rb +++ b/db/migrate/20220211204841_move_to_fx_functions.rb @@ -1,6 +1,5 @@ class MoveToFxFunctions < ActiveRecord::Migration def up - execute("DROP TRIGGER update_donations_fts ON donations") execute("DROP TRIGGER update_supporters_fts ON supporters") execute("DROP TRIGGER update_supporters_phone_index ON supporters") diff --git a/db/migrate/20220606201226_create_nonprofit_s3_keys.rb b/db/migrate/20220606201226_create_nonprofit_s3_keys.rb index b4477fa39..658d5112e 100644 --- a/db/migrate/20220606201226_create_nonprofit_s3_keys.rb +++ b/db/migrate/20220606201226_create_nonprofit_s3_keys.rb @@ -2,9 +2,9 @@ class CreateNonprofitS3Keys < ActiveRecord::Migration def change create_table :nonprofit_s3_keys do |t| t.references :nonprofit, index: true - t.string :access_key_id, required:true - t.string :secret_access_key, required:true - t.string :bucket_name, required:true + t.string :access_key_id, required: true + t.string :secret_access_key, required: true + t.string :bucket_name, required: true t.string :region, required: true t.timestamps null: false diff --git a/db/migrate/20220713192154_add_modern_achievements.rb b/db/migrate/20220713192154_add_modern_achievements.rb index ff5c91893..6050576cb 100644 --- a/db/migrate/20220713192154_add_modern_achievements.rb +++ b/db/migrate/20220713192154_add_modern_achievements.rb @@ -2,13 +2,13 @@ class AddModernAchievements < ActiveRecord::Migration module TemporaryConcern extend ActiveSupport::Concern - included do + included do serialize :achievements, Array serialize :categories, Array end end - def change + def change add_column :nonprofits, :achievements_json, :jsonb add_column :nonprofits, :categories_json, :jsonb @@ -19,15 +19,15 @@ def change np.achievements_json = np.achievements unless np.save puts "NP ##{np.id} could not be saved" - np.save(validate:false) + np.save(validate: false) end np.reload - + raise "NP ##{np.id} does not have identical values" if np.achievements_json != np.achievements end end end - + rename_column :nonprofits, :achievements, :achievements_legacy rename_column :nonprofits, :categories, :categories_legacy diff --git a/db/migrate/20221019183611_create_widget_descriptions.rb b/db/migrate/20221019183611_create_widget_descriptions.rb index 124013cd5..6dc128684 100644 --- a/db/migrate/20221019183611_create_widget_descriptions.rb +++ b/db/migrate/20221019183611_create_widget_descriptions.rb @@ -1,7 +1,7 @@ class CreateWidgetDescriptions < ActiveRecord::Migration def change create_table :widget_descriptions do |t| - t.string :houid, null: false, index:{unique:true} + t.string :houid, null: false, index: {unique: true} t.string :custom_recurring_donation_phrase t.jsonb :custom_amounts t.jsonb :postfix_element diff --git a/db/migrate/20230227171719_add_lockable_to_user.rb b/db/migrate/20230227171719_add_lockable_to_user.rb index c82927a72..ade731612 100644 --- a/db/migrate/20230227171719_add_lockable_to_user.rb +++ b/db/migrate/20230227171719_add_lockable_to_user.rb @@ -1,7 +1,7 @@ class AddLockableToUser < ActiveRecord::Migration def change - add_column :users, :failed_attempts, :integer, default: 0, null: false - add_column :users, :unlock_token, :string - add_column :users, :locked_at, :datetime + add_column :users, :failed_attempts, :integer, default: 0, null: false + add_column :users, :unlock_token, :string + add_column :users, :locked_at, :datetime end end diff --git a/db/migrate/20230307171832_update_function_update_phone_index_on_supporters_to_version_2.rb b/db/migrate/20230307171832_update_function_update_phone_index_on_supporters_to_version_2.rb index 4ff11da17..372467066 100644 --- a/db/migrate/20230307171832_update_function_update_phone_index_on_supporters_to_version_2.rb +++ b/db/migrate/20230307171832_update_function_update_phone_index_on_supporters_to_version_2.rb @@ -1,6 +1,5 @@ class UpdateFunctionUpdatePhoneIndexOnSupportersToVersion2 < ActiveRecord::Migration def change - # we need to drop trigger and then re-add, after the function update drop_trigger :update_supporters_phone_index, on: :supporters, version: 1, revert_to_version: 1 update_function :update_phone_index_on_supporters, version: 2, revert_to_version: 1 diff --git a/db/migrate/20230420211338_recaptcha_rejections_to_json.rb b/db/migrate/20230420211338_recaptcha_rejections_to_json.rb index 8b55dba63..7a91f5dc4 100644 --- a/db/migrate/20230420211338_recaptcha_rejections_to_json.rb +++ b/db/migrate/20230420211338_recaptcha_rejections_to_json.rb @@ -5,7 +5,7 @@ def up ALTER TABLE "recaptcha_rejections" ALTER COLUMN "details" TYPE jsonb USING details::jsonb SQL end - + def down execute <<-SQL ALTER TABLE "recaptcha_rejections" ALTER COLUMN "details" TYPE text USING details::text diff --git a/db/migrate/20230424163001_create_ticket_purchases.rb b/db/migrate/20230424163001_create_ticket_purchases.rb index 8cb7a5ea1..668f197da 100644 --- a/db/migrate/20230424163001_create_ticket_purchases.rb +++ b/db/migrate/20230424163001_create_ticket_purchases.rb @@ -6,7 +6,7 @@ class CreateTicketPurchases < ActiveRecord::Migration def change create_table :ticket_purchases do |t| - t.string "houid", null: false + t.string "houid", null: false t.references :ticket t.timestamps null: false diff --git a/db/migrate/20230427003235_update_ticket_purchase.rb b/db/migrate/20230427003235_update_ticket_purchase.rb index 2d88654b1..870d388c7 100644 --- a/db/migrate/20230427003235_update_ticket_purchase.rb +++ b/db/migrate/20230427003235_update_ticket_purchase.rb @@ -1,6 +1,5 @@ class UpdateTicketPurchase < ActiveRecord::Migration def change - remove_column :ticket_purchases, :ticket_id add_reference :tickets, :ticket_purchase, index: true diff --git a/db/migrate/20230711150901_create_drip_email_lists.rb b/db/migrate/20230711150901_create_drip_email_lists.rb index 21184328d..38c3a5eed 100644 --- a/db/migrate/20230711150901_create_drip_email_lists.rb +++ b/db/migrate/20230711150901_create_drip_email_lists.rb @@ -1,8 +1,7 @@ - class CreateDripEmailLists < ActiveRecord::Migration def change create_table :drip_email_lists do |t| - t.string :mailchimp_list_id, required:true + t.string :mailchimp_list_id, required: true end end end diff --git a/db/migrate/20250329192208_create_active_storage_variant_records.active_storage.rb b/db/migrate/20250329192208_create_active_storage_variant_records.active_storage.rb index 94ac83af0..95fd27fa6 100644 --- a/db/migrate/20250329192208_create_active_storage_variant_records.active_storage.rb +++ b/db/migrate/20250329192208_create_active_storage_variant_records.active_storage.rb @@ -8,20 +8,21 @@ def change t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type t.string :variation_digest, null: false - t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true + t.index %i[blob_id variation_digest], name: "index_active_storage_variant_records_uniqueness", unique: true t.foreign_key :active_storage_blobs, column: :blob_id end end private - def primary_key_type - config = Rails.configuration.generators - config.options[config.orm][:primary_key_type] || :primary_key - end - def blobs_primary_key_type - pkey_name = connection.primary_key(:active_storage_blobs) - pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } - pkey_column.bigint? ? :bigint : pkey_column.type - end + def primary_key_type + config = Rails.configuration.generators + config.options[config.orm][:primary_key_type] || :primary_key + end + + def blobs_primary_key_type + pkey_name = connection.primary_key(:active_storage_blobs) + pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } + pkey_column.bigint? ? :bigint : pkey_column.type + end end diff --git a/db/seeds.rb b/db/seeds.rb index 0855c1077..d7078cfa6 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -3,4 +3,4 @@ bp.name = "Default billing plan" bp.amount = 0 bp.percentage_fee = 0 -bp.save! \ No newline at end of file +bp.save! diff --git a/gems/ruby-param-validation/Rakefile b/gems/ruby-param-validation/Rakefile index 1f33d053b..0873b68cf 100644 --- a/gems/ruby-param-validation/Rakefile +++ b/gems/ruby-param-validation/Rakefile @@ -1,9 +1,9 @@ -require 'rake/testtask' +require "rake/testtask" Rake::TestTask.new do |t| - t.libs << 'test' - t.test_files = FileList['test/test*.rb', 'test/*test.rb'] + t.libs << "test" + t.test_files = FileList["test/test*.rb", "test/*test.rb"] end desc "Run tests" -task :default => :test \ No newline at end of file +task default: :test diff --git a/gems/ruby-param-validation/lib/param_validation.rb b/gems/ruby-param-validation/lib/param_validation.rb index 84fd73553..473faf36c 100644 --- a/gems/ruby-param-validation/lib/param_validation.rb +++ b/gems/ruby-param-validation/lib/param_validation.rb @@ -1,14 +1,13 @@ -require 'json' -require 'chronic' +require "json" +require "chronic" class ParamValidation - # Given a hash of data and a validation hash, check all the validations, raising an Error on the first invalid key # @raise [ValidationError] if one or more of the validations fail. def initialize(data, validations) errors = [] validations.each do |key, validators| - val = key === :root ? data : (data[key] || data[key.to_s] || data[key.to_sym]) + val = (key === :root) ? data : (data[key] || data[key.to_s] || data[key.to_sym]) next if validators[:required].nil? && val.nil? validators.each do |name, arg| validator = @@validators[name] @@ -23,21 +22,31 @@ def initialize(data, validations) if errors.length == 1 raise ValidationError.new(errors[0][:msg], errors[0][:data]) elsif errors.length > 1 - msg = errors.collect {|e| e[:msg]}.join('\n') - raise ValidationError.new(msg, errors.collect{|e| e[:data]}) + msg = errors.collect { |e| e[:msg] }.join('\n') + raise ValidationError.new(msg, errors.collect { |e| e[:data] }) end end - def self.messages; @@messages; end + def self.messages + @@messages + end + def self.set_message(name, &block) @@messages[name] = block end - def self.validators; @@validators; end + def self.validators + @@validators + end + def self.add_validator(name, &block) @@validators[name] = block end - def self.structure_validators; @@structure_validators; end + + def self.structure_validators + @@structure_validators + end + def self.add_structure_validator(name, &block) @@structure_validators[name] = block end @@ -47,64 +56,122 @@ def self.add_structure_validator(name, &block) # - arg is the argument passed into the validator (eg for {required: true}, it is `true`) # - data is the entire set of data @@validators = { - required: lambda {|val, arg, data| !val.nil?}, - absent: lambda {|val, arg, data| val.nil?}, - not_blank: lambda {|val, arg, data| val.is_a?(String) && val.length > 0}, - not_included_in: lambda {|val, arg, data| !arg.include?(val) rescue false}, - included_in: lambda {|val, arg, data| arg.include?(val) rescue false}, - format: lambda {|val, arg, data| val =~ arg rescue false}, - is_integer: lambda {|val, arg, data| val.is_a?(Integer) || val =~ /\A[+-]?\d+\Z/}, - is_float: lambda {|val, arg, data| val.is_a?(Float) || (!!Float(val) rescue false) }, - min_length: lambda {|val, arg, data| val.length >= arg rescue false}, - max_length: lambda {|val, arg, data| val.length <= arg rescue false}, - length_range: lambda {|val, arg, data| arg.cover?(val.length) rescue false}, - length_equals: lambda {|val, arg, data| val.length == arg}, - is_reference: lambda{|val, arg, data| (val.is_a?(Integer)&& val >=0) || val =~ /\A\d+\Z/ || val == ''}, - equals: lambda {|val, arg, data| val == arg}, - min: lambda {|val, arg, data| val >= arg rescue false}, - max: lambda {|val, arg, data| val <= arg rescue false}, - is_array: lambda {|val, arg, data| val.is_a?(Array)}, - is_hash: lambda {|val, arg, data| val.is_a?(Hash) || val.is_a?(ActionController::Parameters)}, - is_json: lambda {|val, arg, data| ParamValidation.is_valid_json?(val)}, - in_range: lambda {|val, arg, data| arg.cover?(val) rescue false}, - is_a: lambda {|val, arg, data| arg.kind_of?(Enumerable) ? arg.any? {|i| val.is_a?(i)} : val.is_a?(arg)}, - can_be_date: lambda {|val, arg, data| val.is_a?(Date) || val.is_a?(DateTime) || Chronic.parse(val)}, - array_of_hashes: lambda {|val, arg, data| data.is_a?(Array) && data.map{|pair| ParamValidation.new(pair.to_h, arg)}.all?} + required: lambda { |val, arg, data| !val.nil? }, + absent: lambda { |val, arg, data| val.nil? }, + not_blank: lambda { |val, arg, data| val.is_a?(String) && val.length > 0 }, + not_included_in: lambda { |val, arg, data| + begin + !arg.include?(val) + rescue + false + end + }, + included_in: lambda { |val, arg, data| + begin + arg.include?(val) + rescue + false + end + }, + format: lambda { |val, arg, data| + begin + val =~ arg + rescue + false + end + }, + is_integer: lambda { |val, arg, data| val.is_a?(Integer) || val =~ /\A[+-]?\d+\Z/ }, + is_float: lambda { |val, arg, data| + val.is_a?(Float) || begin + !!Float(val) + rescue + false + end + }, + min_length: lambda { |val, arg, data| + begin + val.length >= arg + rescue + false + end + }, + max_length: lambda { |val, arg, data| + begin + val.length <= arg + rescue + false + end + }, + length_range: lambda { |val, arg, data| + begin + arg.cover?(val.length) + rescue + false + end + }, + length_equals: lambda { |val, arg, data| val.length == arg }, + is_reference: lambda { |val, arg, data| (val.is_a?(Integer) && val >= 0) || val =~ /\A\d+\Z/ || val == "" }, + equals: lambda { |val, arg, data| val == arg }, + min: lambda { |val, arg, data| + begin + val >= arg + rescue + false + end + }, + max: lambda { |val, arg, data| + begin + val <= arg + rescue + false + end + }, + is_array: lambda { |val, arg, data| val.is_a?(Array) }, + is_hash: lambda { |val, arg, data| val.is_a?(Hash) || val.is_a?(ActionController::Parameters) }, + is_json: lambda { |val, arg, data| ParamValidation.is_valid_json?(val) }, + in_range: lambda { |val, arg, data| + begin + arg.cover?(val) + rescue + false + end + }, + is_a: lambda { |val, arg, data| arg.is_a?(Enumerable) ? arg.any? { |i| val.is_a?(i) } : val.is_a?(arg) }, + can_be_date: lambda { |val, arg, data| val.is_a?(Date) || val.is_a?(DateTime) || Chronic.parse(val) }, + array_of_hashes: lambda { |val, arg, data| data.is_a?(Array) && data.map { |pair| ParamValidation.new(pair.to_h, arg) }.all? } } @@messages = { - required: lambda {|h| "#{h[:key]} is required"}, - absent: lambda {|h| "#{h[:key]} must not be present"}, - not_blank: lambda {|h| "#{h[:key]} must not be blank"}, - not_included_in: lambda {|h| "#{h[:key]} must not be included in #{h[:arg].join(", ")}"}, - included_in: lambda {|h|"#{h[:key]} must be one of #{h[:arg].join(", ")}"}, - format: lambda {|h|"#{h[:key]} doesn't have the right format"}, - is_integer: lambda {|h|"#{h[:key]} should be an integer"}, - is_float: lambda {|h|"#{h[:key]} should be a float"}, - min_length: lambda {|h|"#{h[:key]} has a minimum length of #{h[:arg]}"}, - max_length: lambda {|h|"#{h[:key]} has a maximum length of #{h[:arg]}"}, - length_range: lambda {|h|"#{h[:key]} should have a length within #{h[:arg]}"}, - length_equals: lambda {|h|"#{h[:key]} should have a length of #{h[:arg]}"}, - is_reference: lambda{|h| "#{h[:key]} should be an integer or blank"}, - equals: lambda {|h|"#{h[:key]} should equal #{h[:arg]}"}, - min: lambda {|h|"#{h[:key]} must be at least #{h[:arg]}"}, - max: lambda {|h|"#{h[:key]} cannot be more than #{h[:arg]}"}, - in_range: lambda {|h|"#{h[:key]} should be within #{h[:arg]}"}, - is_json: lambda {|h| "#{h[:key]} should be valid JSON"}, - is_hash: lambda {|h| "#{h[:key]} should be a hash"}, - is_a: lambda {|h| "#{h[:key]} should be of the type(s): #{h[:arg].kind_of?(Enumerable) ? h[:arg].join(', '): h[:arg]}"}, - can_be_date: lambda {|h| "#{h[:key]} should be a datetime or be parsable as one"}, - array_of_hashes: lambda {|h| "Please pass in an array of hashes"} + required: lambda { |h| "#{h[:key]} is required" }, + absent: lambda { |h| "#{h[:key]} must not be present" }, + not_blank: lambda { |h| "#{h[:key]} must not be blank" }, + not_included_in: lambda { |h| "#{h[:key]} must not be included in #{h[:arg].join(", ")}" }, + included_in: lambda { |h| "#{h[:key]} must be one of #{h[:arg].join(", ")}" }, + format: lambda { |h| "#{h[:key]} doesn't have the right format" }, + is_integer: lambda { |h| "#{h[:key]} should be an integer" }, + is_float: lambda { |h| "#{h[:key]} should be a float" }, + min_length: lambda { |h| "#{h[:key]} has a minimum length of #{h[:arg]}" }, + max_length: lambda { |h| "#{h[:key]} has a maximum length of #{h[:arg]}" }, + length_range: lambda { |h| "#{h[:key]} should have a length within #{h[:arg]}" }, + length_equals: lambda { |h| "#{h[:key]} should have a length of #{h[:arg]}" }, + is_reference: lambda { |h| "#{h[:key]} should be an integer or blank" }, + equals: lambda { |h| "#{h[:key]} should equal #{h[:arg]}" }, + min: lambda { |h| "#{h[:key]} must be at least #{h[:arg]}" }, + max: lambda { |h| "#{h[:key]} cannot be more than #{h[:arg]}" }, + in_range: lambda { |h| "#{h[:key]} should be within #{h[:arg]}" }, + is_json: lambda { |h| "#{h[:key]} should be valid JSON" }, + is_hash: lambda { |h| "#{h[:key]} should be a hash" }, + is_a: lambda { |h| "#{h[:key]} should be of the type(s): #{h[:arg].is_a?(Enumerable) ? h[:arg].join(", ") : h[:arg]}" }, + can_be_date: lambda { |h| "#{h[:key]} should be a datetime or be parsable as one" }, + array_of_hashes: lambda { |h| "Please pass in an array of hashes" } } # small utility for testing json validity def self.is_valid_json?(str) - begin - JSON.parse(str) - return true - rescue => e - return false - end + JSON.parse(str) + true + rescue + false end # Special error class that holds all the error data for reference @@ -125,6 +192,4 @@ def initialize(msg, data) super(msg) end end - end - diff --git a/gems/ruby-param-validation/param_validation.gemspec b/gems/ruby-param-validation/param_validation.gemspec index a08508a88..fc626f1db 100644 --- a/gems/ruby-param-validation/param_validation.gemspec +++ b/gems/ruby-param-validation/param_validation.gemspec @@ -1,15 +1,14 @@ Gem::Specification.new do |s| - s.name = 'param_validation' - s.version = '0.0.2' - s.date = '2017-07-21' - s.summary = 'Simple hash validator' - s.description = 'A hash validator that throws exceptions, with a lot of customization options' - s.authors = ['Jay R Bolton'] - s.email = 'jayrbolton@gmail.com' - s.files = 'lib/param_validation.rb' - s.homepage = 'https://github.com/jayrbolton/ruby-param-validation' - s.license = 'MIT' + s.name = "param_validation" + s.version = "0.0.2" + s.summary = "Simple hash validator" + s.description = "A hash validator that throws exceptions, with a lot of customization options" + s.authors = ["Jay R Bolton"] + s.email = "jayrbolton@gmail.com" + s.files = "lib/param_validation.rb" + s.homepage = "https://github.com/jayrbolton/ruby-param-validation" + s.license = "MIT" - s.add_runtime_dependency 'chronic' - s.add_runtime_dependency 'actionpack', ">= 5" + s.add_runtime_dependency "chronic" + s.add_runtime_dependency "actionpack", ">= 5" end diff --git a/gems/ruby-param-validation/test/param_validation_test.rb b/gems/ruby-param-validation/test/param_validation_test.rb index a58262efd..651a063a0 100644 --- a/gems/ruby-param-validation/test/param_validation_test.rb +++ b/gems/ruby-param-validation/test/param_validation_test.rb @@ -1,8 +1,7 @@ -require './lib/param_validation.rb' -require 'minitest/autorun' +require "./lib/param_validation" +require "minitest/autorun" class ParamValidationTest < Minitest::Test - def setup end @@ -11,54 +10,63 @@ def test_required rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + # If a key is not required, then don't run the tests on it def test_not_required_and_absent_then_tests_do_not_run ParamValidation.new({}, {x: {max: 100}}) assert true end + def test_not_blank_fail - begin; ParamValidation.new({x: ''}, {x: {not_blank: true}}) + begin; ParamValidation.new({x: ""}, {x: {not_blank: true}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_not_blank_fail_nil begin; ParamValidation.new({x: nil}, {x: {not_blank: true, required: true}}) rescue ParamValidation::ValidationError => e; e; end - assert(e.data.one?{|i| i[:name] == :not_blank && i[:key] == :x}) - assert(e.data.one?{|i| i[:name] == :required && i[:key] == :x}) + assert(e.data.one? { |i| i[:name] == :not_blank && i[:key] == :x }) + assert(e.data.one? { |i| i[:name] == :required && i[:key] == :x }) end + def test_not_blank_succeed - ParamValidation.new({x: 'x'}, {x: {not_blank: true}}) + ParamValidation.new({x: "x"}, {x: {not_blank: true}}) assert true end + def test_require_no_err begin; ParamValidation.new({x: 1}, {x: {required: true}}) rescue ParamValidation::ValidationError => e; end assert e.nil? end + def test_absent begin; ParamValidation.new({x: 1}, {x: {absent: true}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_not_included_in begin; ParamValidation.new({x: 1}, {x: {not_included_in: [1]}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_included_in begin; ParamValidation.new({x: 1}, {x: {included_in: [2]}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_format - begin; ParamValidation.new({x: 'x'}, {x: {format: /y/}}) + begin; ParamValidation.new({x: "x"}, {x: {format: /y/}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end def test_is_reference_string - begin; ParamValidation.new({x: '-0'}, {x: {is_reference: true}}) + begin; ParamValidation.new({x: "-0"}, {x: {is_reference: true}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end @@ -70,79 +78,91 @@ def test_is_reference_negative_integer end def test_is_reference_passes - ParamValidation.new({x: '0'}, {x: {is_reference: true}}) + ParamValidation.new({x: "0"}, {x: {is_reference: true}}) ParamValidation.new({x: 1}, {x: {is_reference: true}}) - ParamValidation.new({x: ''}, {x: {is_reference: true}}) - pass() + ParamValidation.new({x: ""}, {x: {is_reference: true}}) + pass end def test_is_integer - begin; ParamValidation.new({x: 'x'}, {x: {is_integer: true}}) + begin; ParamValidation.new({x: "x"}, {x: {is_integer: true}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_is_float - begin; ParamValidation.new({x: 'x'}, {x: {is_float: true}}) + begin; ParamValidation.new({x: "x"}, {x: {is_float: true}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_min_length begin; ParamValidation.new({x: []}, {x: {min_length: 2}}) rescue ParamValidation::ValidationError => e; e; end assert_equal :x, e.data[:key] end + def test_max_length - begin; ParamValidation.new({x: [1,2,3]}, {x: {max_length: 2}}) + begin; ParamValidation.new({x: [1, 2, 3]}, {x: {max_length: 2}}) rescue ParamValidation::ValidationError => e; e; end assert_equal e.data[:key], :x end + def test_length_range - begin; ParamValidation.new({x: [1,2,3,4]}, {x: {length_range: 1..3}}) + begin; ParamValidation.new({x: [1, 2, 3, 4]}, {x: {length_range: 1..3}}) rescue ParamValidation::ValidationError => e; e; end assert_equal e.data[:key], :x end + def test_length_equals - begin; ParamValidation.new({x: [1,2]}, {x: {length_equals: 1}}) + begin; ParamValidation.new({x: [1, 2]}, {x: {length_equals: 1}}) rescue ParamValidation::ValidationError => e; e; end assert_equal e.data[:key], :x end + def test_min begin; ParamValidation.new({x: 1}, {x: {min: 2}}) rescue ParamValidation::ValidationError => e; e; end assert_equal e.data[:key], :x end + def test_max begin; ParamValidation.new({x: 4}, {x: {max: 2}}) rescue ParamValidation::ValidationError => e; e; end assert_equal e.data[:name], :max end + def test_in_range begin; ParamValidation.new({x: 1}, {x: {in_range: 2..4}}) rescue ParamValidation::ValidationError => e; e; end assert_equal e.data[:val], 1 end + def test_equals begin; ParamValidation.new({x: 1}, {x: {equals: 2}}) rescue ParamValidation::ValidationError => e; e; end - assert_equal "x should equal #{2}", e.to_s + assert_equal "x should equal 2", e.to_s end + def test_root_array_of_hashes begin; ParamValidation.new({x: 1}, {root: {array_of_hashes: {x: {required: true}}}}) rescue ParamValidation::ValidationError => e; e; end assert_equal "Please pass in an array of hashes", e.to_s end + def test_root_array_of_hashes_with_nesting_ok - v = ParamValidation.new([{'x' => 1}, {x: 1}], {root: {array_of_hashes: {x: {is_integer: true}}}}) + v = ParamValidation.new([{"x" => 1}, {x: 1}], {root: {array_of_hashes: {x: {is_integer: true}}}}) assert_equal v, v # test that it does not raise end + def test_root_array_of_hashes_with_nesting - begin; ParamValidation.new([{x: 1}, {x: 'hi'}], {root: {array_of_hashes: {x: {is_integer: true}}}}) + begin; ParamValidation.new([{x: 1}, {x: "hi"}], {root: {array_of_hashes: {x: {is_integer: true}}}}) rescue ParamValidation::ValidationError => e; e; end assert_equal "x should be an integer", e.to_s end def test_is_json_with_string - begin; ParamValidation.new({x: '[[[[[[['}, {x: {is_json: true}}) + begin; ParamValidation.new({x: "[[[[[[["}, {x: {is_json: true}}) rescue ParamValidation::ValidationError => e; e; end assert_equal "x should be valid JSON", e.to_s end @@ -160,50 +180,50 @@ def test_is_a_single rescue ParamValidation::ValidationError => e e end - assert_equal 'x should be of the type(s): Integer', e.to_s + assert_equal "x should be of the type(s): Integer", e.to_s end - def test_is_a_multiple - ParamValidation.new({x: 5.6}, {x: {is_a: [Integer,Float]}}) + ParamValidation.new({x: 5.6}, {x: {is_a: [Integer, Float]}}) begin ParamValidation.new({x: 5.6}, {x: {is_a: [Integer, Array]}}) rescue ParamValidation::ValidationError => e e end - assert_equal 'x should be of the type(s): Integer, Array', e.to_s + assert_equal "x should be of the type(s): Integer, Array", e.to_s end def test_can_be_date - ParamValidation.new({x: Date.new()}, {x: {can_be_date: true}}) - ParamValidation.new({x: DateTime.new()}, {x: {can_be_date: true}}) - ParamValidation.new({x: '2017-05-15T12:00:00.000Z'}, {x: {can_be_date: true}}) - ParamValidation.new({x: '2017-05-15'}, {x: {can_be_date: true}}) + ParamValidation.new({x: Date.new}, {x: {can_be_date: true}}) + ParamValidation.new({x: DateTime.new}, {x: {can_be_date: true}}) + ParamValidation.new({x: "2017-05-15T12:00:00.000Z"}, {x: {can_be_date: true}}) + ParamValidation.new({x: "2017-05-15"}, {x: {can_be_date: true}}) begin - ParamValidation.new({x: 'not_a _date'}, {x: {can_be_date: true}}) + ParamValidation.new({x: "not_a _date"}, {x: {can_be_date: true}}) rescue ParamValidation::ValidationError => e e end - assert_equal 'x should be a datetime or be parsable as one', e.to_s + assert_equal "x should be a datetime or be parsable as one", e.to_s end def test_add_validator - ParamValidation.add_validator(:dollars){|val, arg, data| val =~ /^\d+(\.\d\d)?$/} + ParamValidation.add_validator(:dollars) { |val, arg, data| val =~ /^\d+(\.\d\d)?$/ } begin - ParamValidation.new({x: 'hi'}, {x: {dollars: true}}) + ParamValidation.new({x: "hi"}, {x: {dollars: true}}) rescue ParamValidation::ValidationError => e e end assert_equal :dollars, e.data[:name] end + def test_set_message - ParamValidation.add_validator(:dollars){|val, arg, data| val =~ /^\d+(\.\d\d)?$/} - ParamValidation.set_message(:dollars){|h| "#{h[:key]} must be a dollar amount"} + ParamValidation.add_validator(:dollars) { |val, arg, data| val =~ /^\d+(\.\d\d)?$/ } + ParamValidation.set_message(:dollars) { |h| "#{h[:key]} must be a dollar amount" } begin - ParamValidation.new({x: 'hi'}, {x: {dollars: true}}) + ParamValidation.new({x: "hi"}, {x: {dollars: true}}) rescue ParamValidation::ValidationError => e e end diff --git a/gems/ruby-qx/lib/qx.rb b/gems/ruby-qx/lib/qx.rb index b600bd2e7..9c89b68bf 100644 --- a/gems/ruby-qx/lib/qx.rb +++ b/gems/ruby-qx/lib/qx.rb @@ -1,5 +1,5 @@ -require 'active_record' -require 'colorize' +require "active_record" +require "colorize" class Qx ## @@ -17,7 +17,6 @@ def self.config(h) # Qx.new, only used internally def initialize(tree) @tree = tree - self end def self.transaction(&block) @@ -27,27 +26,27 @@ def self.transaction(&block) end def self.parse_select(expr) - str = 'SELECT' + str = "SELECT" if expr[:DISTINCT_ON] - str += " DISTINCT ON (#{expr[:DISTINCT_ON].map(&:to_s).join(', ')})" + str += " DISTINCT ON (#{expr[:DISTINCT_ON].map(&:to_s).join(", ")})" elsif expr[:DISTINCT] - str += ' DISTINCT' + str += " DISTINCT" end - str += ' ' + expr[:SELECT].map { |expr| expr.is_a?(Qx) ? expr.parse : expr }.join(', ') - throw ArgumentError.new('FROM clause is missing for SELECT') unless expr[:FROM] - str += ' FROM ' + expr[:FROM] + str += " " + expr[:SELECT].map { |expr| expr.is_a?(Qx) ? expr.parse : expr }.join(", ") + throw ArgumentError.new("FROM clause is missing for SELECT") unless expr[:FROM] + str += " FROM " + expr[:FROM] str += expr[:JOIN].map { |from, cond| " JOIN #{from} ON #{cond}" }.join if expr[:JOIN] str += expr[:LEFT_JOIN].map { |from, cond| " LEFT JOIN #{from} ON #{cond}" }.join if expr[:LEFT_JOIN] str += expr[:LEFT_OUTER_JOIN].map { |from, cond| " LEFT OUTER JOIN #{from} ON #{cond}" }.join if expr[:LEFT_OUTER_JOIN] - str += expr[:JOIN_LATERAL].map {|i| " JOIN LATERAL (#{i[:select_statement]}) #{i[:join_name]} ON #{i[:success_condition]}"}.join if expr[:JOIN_LATERAL] - - str += expr[:LEFT_JOIN_LATERAL].map {|i| " LEFT JOIN LATERAL (#{i[:select_statement]}) #{i[:join_name]} ON #{i[:success_condition]}"}.join if expr[:LEFT_JOIN_LATERAL] - str += ' WHERE ' + expr[:WHERE].map { |w| "(#{w})" }.join(' AND ') if expr[:WHERE] - str += ' GROUP BY ' + expr[:GROUP_BY].join(', ') if expr[:GROUP_BY] - str += ' HAVING ' + expr[:HAVING].map { |h| "(#{h})" }.join(' AND ') if expr[:HAVING] - str += ' ORDER BY ' + expr[:ORDER_BY].map { |col, order| col + (order ? ' ' + order : '') }.join(', ') if expr[:ORDER_BY] - str += ' LIMIT ' + expr[:LIMIT] if expr[:LIMIT] - str += ' OFFSET ' + expr[:OFFSET] if expr[:OFFSET] + str += expr[:JOIN_LATERAL].map { |i| " JOIN LATERAL (#{i[:select_statement]}) #{i[:join_name]} ON #{i[:success_condition]}" }.join if expr[:JOIN_LATERAL] + + str += expr[:LEFT_JOIN_LATERAL].map { |i| " LEFT JOIN LATERAL (#{i[:select_statement]}) #{i[:join_name]} ON #{i[:success_condition]}" }.join if expr[:LEFT_JOIN_LATERAL] + str += " WHERE " + expr[:WHERE].map { |w| "(#{w})" }.join(" AND ") if expr[:WHERE] + str += " GROUP BY " + expr[:GROUP_BY].join(", ") if expr[:GROUP_BY] + str += " HAVING " + expr[:HAVING].map { |h| "(#{h})" }.join(" AND ") if expr[:HAVING] + str += " ORDER BY " + expr[:ORDER_BY].map { |col, order| col + (order ? " " + order : "") }.join(", ") if expr[:ORDER_BY] + str += " LIMIT " + expr[:LIMIT] if expr[:LIMIT] + str += " OFFSET " + expr[:OFFSET] if expr[:OFFSET] str = "(#{str}) AS #{expr[:AS]}" if expr[:AS] str = "EXPLAIN #{str}" if expr[:EXPLAIN] str @@ -57,9 +56,9 @@ def self.parse_select(expr) # http://www.postgresql.org/docs/9.0/static/sql-commands.html def self.parse(expr) if expr.is_a?(String) - return expr # already parsed + expr # already parsed elsif expr.is_a?(Array) - return expr.join(',') + expr.join(",") else str = "" if expr[:WITHS].present? @@ -70,45 +69,45 @@ def self.parse(expr) str += " " # add a splitting space before the rest of the query end if expr[:INSERT_INTO] - str += "INSERT INTO #{expr[:INSERT_INTO]} (#{expr[:INSERT_COLUMNS].join(', ')})" - throw ArgumentError.new('VALUES (or SELECT) clause is missing for INSERT INTO') unless expr[:VALUES] || expr[:SELECT] + str += "INSERT INTO #{expr[:INSERT_INTO]} (#{expr[:INSERT_COLUMNS].join(", ")})" + throw ArgumentError.new("VALUES (or SELECT) clause is missing for INSERT INTO") unless expr[:VALUES] || expr[:SELECT] throw ArgumentError.new("For safety, you can't use SELECT without insert columns for an INSERT INTO") if !expr[:INSERT_COLUMNS] && expr[:SELECT] - if expr[:SELECT] - str += ' ' + parse_select(expr) + str += if expr[:SELECT] + " " + parse_select(expr) else - str += " VALUES #{expr[:VALUES].map { |vals| "(#{vals.join(', ')})" }.join(', ')}" + " VALUES #{expr[:VALUES].map { |vals| "(#{vals.join(", ")})" }.join(", ")}" end if expr[:ON_CONFLICT] - str += ' ON CONFLICT' + str += " ON CONFLICT" if expr[:CONFLICT_COLUMNS] - str += " (#{expr[:CONFLICT_COLUMNS].join(', ')})" + str += " (#{expr[:CONFLICT_COLUMNS].join(", ")})" elsif expr[:ON_CONSTRAINT] str += " ON CONSTRAINT #{expr[:ON_CONSTRAINT]}" end - str += ' DO NOTHING' if !expr[:CONFLICT_UPSERT] + str += " DO NOTHING" if !expr[:CONFLICT_UPSERT] if expr[:CONFLICT_UPSERT] - set_str = expr[:INSERT_COLUMNS].select{|i| i != 'created_at'}.map{|i| "#{i} = EXCLUDED.#{i}" } - str += " DO UPDATE SET #{set_str.join(', ')}" + set_str = expr[:INSERT_COLUMNS].select { |i| i != "created_at" }.map { |i| "#{i} = EXCLUDED.#{i}" } + str += " DO UPDATE SET #{set_str.join(", ")}" end end - str += ' RETURNING ' + expr[:RETURNING].join(', ') if expr[:RETURNING] + str += " RETURNING " + expr[:RETURNING].join(", ") if expr[:RETURNING] elsif expr[:SELECT] str += parse_select(expr) elsif expr[:DELETE_FROM] - str += 'DELETE FROM ' + expr[:DELETE_FROM] - throw ArgumentError.new('WHERE clause is missing for DELETE FROM') unless expr[:WHERE] - str += ' WHERE ' + expr[:WHERE].map { |w| "(#{w})" }.join(' AND ') - str += ' RETURNING ' + expr[:RETURNING].join(', ') if expr[:RETURNING] + str += "DELETE FROM " + expr[:DELETE_FROM] + throw ArgumentError.new("WHERE clause is missing for DELETE FROM") unless expr[:WHERE] + str += " WHERE " + expr[:WHERE].map { |w| "(#{w})" }.join(" AND ") + str += " RETURNING " + expr[:RETURNING].join(", ") if expr[:RETURNING] elsif expr[:UPDATE] - str += 'UPDATE ' + expr[:UPDATE] - throw ArgumentError.new('SET clause is missing for UPDATE') unless expr[:SET] - throw ArgumentError.new('WHERE clause is missing for UPDATE') unless expr[:WHERE] - str += ' SET ' + expr[:SET] - str += ' FROM ' + expr[:FROM] if expr[:FROM] - str += ' WHERE ' + expr[:WHERE].map { |w| "(#{w})" }.join(' AND ') - str += ' ' + expr[:ON_CONFLICT] if expr[:ON_CONFLICT] - str += ' RETURNING ' + expr[:RETURNING].join(', ') if expr[:RETURNING] + str += "UPDATE " + expr[:UPDATE] + throw ArgumentError.new("SET clause is missing for UPDATE") unless expr[:SET] + throw ArgumentError.new("WHERE clause is missing for UPDATE") unless expr[:WHERE] + str += " SET " + expr[:SET] + str += " FROM " + expr[:FROM] if expr[:FROM] + str += " WHERE " + expr[:WHERE].map { |w| "(#{w})" }.join(" AND ") + str += " " + expr[:ON_CONFLICT] if expr[:ON_CONFLICT] + str += " RETURNING " + expr[:RETURNING].join(", ") if expr[:RETURNING] end str end @@ -121,10 +120,10 @@ def parse # Qx.select("id").from("supporters").execute def execute(options = {}) - expr = Qx.parse(@tree).to_s.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') + expr = Qx.parse(@tree).to_s.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "") Qx.execute_raw(expr, options) end - alias ex execute + alias_method :ex, :execute # Can pass in an expression string or another Qx object # Qx.execute("SELECT id FROM table_name", {format: 'csv'}) @@ -145,7 +144,7 @@ def self.execute_raw(expr, options = {}) end result = ActiveRecord::Base.connection.execute(expr) result.map_types!(@@type_map) if @@type_map - if options[:format] == 'csv' + if options[:format] == "csv" data = result.map(&:values) data.unshift((result.first || {}).keys) else @@ -157,7 +156,7 @@ def self.execute_raw(expr, options = {}) end def self.execute_file(path, data = {}, options = {}) - Qx.execute_raw(Qx.interpolate_expr(File.open(path, 'r').read, data), options) + Qx.execute_raw(Qx.interpolate_expr(File.read(path), data), options) end # helpers for JSON conversion @@ -255,7 +254,6 @@ def group_by(*cols) end def order_by(*cols) - orders = /(asc)|(desc)( nulls (first)|(last))?/i # Sanitize out invalid order keywords @tree[:ORDER_BY] = cols.map { |col, order| [col.to_s, order.to_s.downcase.strip.match(order.to_s.downcase) ? order.to_s.upcase : nil] } self @@ -320,16 +318,13 @@ def add_left_outer_join(*joins) self end - def join_lateral(join_name, select_statement, success_condition=true) - + def join_lateral(join_name, select_statement, success_condition = true) @tree[:JOIN_LATERAL] ||= [] @tree[:JOIN_LATERAL].concat([{join_name: join_name, select_statement: select_statement, success_condition: success_condition}]) self end - - def left_join_lateral(join_name, select_statement, success_condition=true) - + def left_join_lateral(join_name, select_statement, success_condition = true) @tree[:LEFT_JOIN_LATERAL] ||= [] @tree[:LEFT_JOIN_LATERAL].concat([{join_name: join_name, select_statement: select_statement, success_condition: success_condition}]) self @@ -378,7 +373,7 @@ def ts end self end - alias timestamps ts + alias_method :timestamps, :ts def returning(*cols) @tree[:RETURNING] = cols.map { |c| Qx.quote_ident(c) } @@ -388,13 +383,13 @@ def returning(*cols) # Vals can be a raw SQL string or a hash of data def set(vals) if vals.is_a? Hash - vals = vals.map { |key, val| "#{Qx.quote_ident(key)} = #{Qx.quote(val)}" }.join(', ') + vals = vals.map { |key, val| "#{Qx.quote_ident(key)} = #{Qx.quote(val)}" }.join(", ") end @tree[:SET] = vals.to_s self end - def on_conflict() + def on_conflict @tree[:ON_CONFLICT] = true self end @@ -409,7 +404,7 @@ def on_constraint(constraint) self end - def upsert(on_index, columns=nil) + def upsert(on_index, columns = nil) @tree[:CONFLICT_UPSERT] = {index: on_index, cols: columns} self end @@ -419,9 +414,13 @@ def explain self end - def with(name, expr, materialized:nil) - materialized_text = !materialized.nil? ? (materialized ? "MATERIALIZED" : "NOT MATERIALIZED") : "" - + def with(name, expr, materialized: nil) + if !materialized.nil? + materialized ? "MATERIALIZED" : "NOT MATERIALIZED" + else + "" + end + raise "expr is not a Qx, that's not safe!" unless expr.is_a? Qx @tree[:WITHS] ||= [] @tree[:WITHS].push({name: name, expr: expr, materialized: materialized}) @@ -429,18 +428,16 @@ def with(name, expr, materialized:nil) self end - # -- Helpers! def self.fetch(table_name, data, options = {}) - expr = Qx.select('*').from(table_name) - if data.is_a?(Hash) - expr = data.reduce(expr) { |acc, pair| acc.and_where("#{pair.first} IN ($vals)", vals: Array(pair.last)) } + expr = Qx.select("*").from(table_name) + expr = if data.is_a?(Hash) + data.reduce(expr) { |acc, pair| acc.and_where("#{pair.first} IN ($vals)", vals: Array(pair.last)) } else - expr = expr.where('id IN ($ids)', ids: Array(data)) + expr.where("id IN ($ids)", ids: Array(data)) end - result = expr.execute(options) - result + expr.execute(options) end # Given a Qx expression, add a LIMIT and OFFSET for pagination @@ -453,11 +450,10 @@ def pp str = parse # Colorize some tokens # TODO indent by paren levels - str = str - .gsub(/(FROM|WHERE|VALUES|SET|SELECT|UPDATE|INSERT INTO|DELETE FROM)/) { Regexp.last_match(1).to_s.blue.bold } - .gsub(/(\(|\))/) { Regexp.last_match(1).to_s.cyan } - .gsub('$Q$', "'") str + .gsub(/(FROM|WHERE|VALUES|SET|SELECT|UPDATE|INSERT INTO|DELETE FROM)/) { Regexp.last_match(1).to_s.blue.bold } + .gsub(/(\(|\))/) { Regexp.last_match(1).to_s.cyan } + .gsub("$Q$", "'") end # -- utils @@ -467,9 +463,9 @@ def pp # Safely interpolate some data into a SQL expression def self.interpolate_expr(expr, data = {}) expr.to_s.gsub(/\$\w+/) do |match| - val = data[match.gsub(/[ \$]*/, '').to_sym] + val = data[match.gsub(/[ \$]*/, "").to_sym] vals = val.is_a?(Array) ? val : [val] - vals.map { |x| Qx.quote(x) }.join(', ') + vals.map { |x| Qx.quote(x) }.join(", ") end end @@ -485,11 +481,11 @@ def self.quote(val) elsif val.is_a?(Time) "'" + val.to_s + "'" # single-quoted times for a little better readability elsif val.nil? - 'NULL' + "NULL" elsif !!val == val # is a boolean val ? "'t'" : "'f'" else - '$Q$' + val.to_s + '$Q$' + "$Q$" + val.to_s + "$Q$" end end @@ -498,13 +494,13 @@ def self.quote_ident(expr) if expr.is_a?(Qx) Qx.parse(expr.tree) else - expr.to_s.split('.').map { |s| s == '*' ? s : "\"#{s}\"" }.join('.') + expr.to_s.split(".").map { |s| (s == "*") ? s : "\"#{s}\"" }.join(".") end end # Remove a clause from the sql tree def remove_clause(name) - name = name.to_s.upcase.tr(' ', '_').to_sym + name = name.to_s.upcase.tr(" ", "_").to_sym @tree.delete(name) self end @@ -533,7 +529,7 @@ def self.get_join_param(js) def self.parse_wheres(clauses) clauses.map do |expr, data| if expr.is_a?(Hash) - expr.map { |key, val| "#{Qx.quote_ident(key)} IN (#{Qx.quote(val)})" }.join(' AND ') + expr.map { |key, val| "#{Qx.quote_ident(key)} IN (#{Qx.quote(val)})" }.join(" AND ") else Qx.interpolate_expr(expr, data) end diff --git a/gems/ruby-qx/qx.gemspec b/gems/ruby-qx/qx.gemspec index dcfcd007b..b1ef184ab 100644 --- a/gems/ruby-qx/qx.gemspec +++ b/gems/ruby-qx/qx.gemspec @@ -1,15 +1,14 @@ Gem::Specification.new do |s| - s.name = 'qx' - s.version = '0.1.1' - s.date = '2016-12-05' - s.summary = 'SQL expression builder' - s.description = 'A expression builder for SQL expressions with Postgresql support' - s.authors = ['Jay R Bolton'] - s.email = 'jayrbolton@gmail.com' - s.files = 'lib/qx.rb' - s.homepage = 'https://github.com/jayrbolton/qx' - s.license = 'MIT' - s.add_runtime_dependency 'colorize', '~> 0.8' - s.add_runtime_dependency 'activerecord', '>= 3.0' - s.add_development_dependency 'minitest', '~> 5.9' + s.name = "qx" + s.version = "0.1.1" + s.summary = "SQL expression builder" + s.description = "A expression builder for SQL expressions with Postgresql support" + s.authors = ["Jay R Bolton"] + s.email = "jayrbolton@gmail.com" + s.files = "lib/qx.rb" + s.homepage = "https://github.com/jayrbolton/qx" + s.license = "MIT" + s.add_runtime_dependency "colorize", "~> 0.8" + s.add_runtime_dependency "activerecord", ">= 3.0" + s.add_development_dependency "minitest", "~> 5.9" end diff --git a/gems/ruby-qx/test/UpsertTest.rb b/gems/ruby-qx/test/UpsertTest.rb index 1638669fe..56ff791b4 100644 --- a/gems/ruby-qx/test/UpsertTest.rb +++ b/gems/ruby-qx/test/UpsertTest.rb @@ -1,20 +1,19 @@ -require './lib/qx.rb' +require "./lib/qx" -require 'minitest/autorun' +require "minitest/autorun" class UpsertTest < Minitest::Test def setup - end def test_upsert - table = 'x' + table = "x" column1 = "a" - column2 = 'b' + column2 = "b" idx = "idx_something_more" result = Qx.insert_into(table).values({column1: column1, column2: column2}).on_conflict.upsert(idx).parse - expected = %Q(INSERT INTO "#{table}" ("column1", "column2") VALUES ($Q$#{column1}$Q$, $Q$#{column2}$Q$) ON CONFLICT ON CONSTRAINT #{idx} DO UPDATE SET "column1" = EXCLUDED."column1", "column2" = EXCLUDED."column2") + expected = %(INSERT INTO "#{table}" ("column1", "column2") VALUES ($Q$#{column1}$Q$, $Q$#{column2}$Q$) ON CONFLICT ON CONSTRAINT #{idx} DO UPDATE SET "column1" = EXCLUDED."column1", "column2" = EXCLUDED."column2") assert_equal(expected, result) end -end \ No newline at end of file +end diff --git a/gems/ruby-qx/test/qx_test.rb b/gems/ruby-qx/test/qx_test.rb index 74fd2ee8f..47f33f98b 100644 --- a/gems/ruby-qx/test/qx_test.rb +++ b/gems/ruby-qx/test/qx_test.rb @@ -1,224 +1,242 @@ -require './lib/qx.rb' -require 'pg' -require 'minitest/autorun' -require 'pry' +require "./lib/qx" +require "pg" +require "minitest/autorun" +require "pry" -ActiveRecord::Base.establish_connection('postgres://admin:password@localhost/qx_test') +ActiveRecord::Base.establish_connection("postgres://admin:password@localhost/qx_test") tm = PG::BasicTypeMapForResults.new(ActiveRecord::Base.connection.raw_connection) Qx.config(type_map: tm) # Execute test schema -Qx.execute_file('./test/test_schema.sql') +Qx.execute_file("./test/test_schema.sql") class QxTest < Minitest::Test - def setup end # Let's just test that the schema was executed def test_execute_file - email = 'uzzzr@example.com' - result = Qx.execute_file('./test/test_insert_user.sql', email: email, id: 1).last + email = "uzzzr@example.com" + result = Qx.execute_file("./test/test_insert_user.sql", email: email, id: 1).last Qx.delete_from(:users).where(id: 1).ex - assert_equal email, result['email'] + assert_equal email, result["email"] end def test_select_from parsed = Qx.select(:id, "name").from(:table_name).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name) + assert_equal parsed, %(SELECT id, name FROM table_name) end + def test_select_distinct_on parsed = Qx.select(:id, "name").distinct_on(:distinct_col1, :distinct_col2).from(:table_name).parse - assert_equal parsed, %Q(SELECT DISTINCT ON (distinct_col1, distinct_col2) id, name FROM table_name) + assert_equal parsed, %(SELECT DISTINCT ON (distinct_col1, distinct_col2) id, name FROM table_name) end + def test_select_distinct parsed = Qx.select(:id, "name").distinct.from(:table_name).parse - assert_equal parsed, %Q(SELECT DISTINCT id, name FROM table_name) + assert_equal parsed, %(SELECT DISTINCT id, name FROM table_name) end def test_select_as parsed = Qx.select(:id, "name").from(:table_name).as(:alias).parse - assert_equal parsed, %Q((SELECT id, name FROM table_name) AS "alias") + assert_equal parsed, %((SELECT id, name FROM table_name) AS "alias") end - + def test_select_where parsed = Qx.select(:id, "name").from(:table_name).where("x = $y OR a = $b", y: 1, b: 2).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name WHERE (x = 1 OR a = 2)) + assert_equal parsed, %(SELECT id, name FROM table_name WHERE (x = 1 OR a = 2)) end + def test_select_where_hash_array parsed = Qx.select(:id, "name").from(:table_name).where([x: 1], ["y = $n", {n: 2}]).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name WHERE ("x" IN (1)) AND (y = 2)) + assert_equal parsed, %(SELECT id, name FROM table_name WHERE ("x" IN (1)) AND (y = 2)) end + def test_select_and_where parsed = Qx.select(:id, "name").from(:table_name).where("x = $y", y: 1).and_where("a = $b", b: 2).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name WHERE (x = 1) AND (a = 2)) + assert_equal parsed, %(SELECT id, name FROM table_name WHERE (x = 1) AND (a = 2)) end + def test_select_and_where_hash parsed = Qx.select(:id, "name").from(:table_name).where("x = $y", y: 1).and_where(a: 2).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name WHERE (x = 1) AND ("a" IN (2))) + assert_equal parsed, %(SELECT id, name FROM table_name WHERE (x = 1) AND ("a" IN (2))) end - + def test_select_and_group_by parsed = Qx.select(:id, "name").from(:table_name).group_by("col1", "col2").parse - assert_equal parsed, %Q(SELECT id, name FROM table_name GROUP BY col1, col2) + assert_equal parsed, %(SELECT id, name FROM table_name GROUP BY col1, col2) end - + def test_select_and_order_by parsed = Qx.select(:id, "name").from(:table_name).order_by("col1", ["col2", "DESC NULLS LAST"]).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name ORDER BY col1 , col2 DESC NULLS LAST) + assert_equal parsed, %(SELECT id, name FROM table_name ORDER BY col1 , col2 DESC NULLS LAST) end def test_select_having parsed = Qx.select(:id, "name").from(:table_name).having("COUNT(col1) > $n", n: 1).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name HAVING (COUNT(col1) > 1)) + assert_equal parsed, %(SELECT id, name FROM table_name HAVING (COUNT(col1) > 1)) end + def test_select_and_having parsed = Qx.select(:id, "name").from(:table_name).having("COUNT(col1) > $n", n: 1).and_having("SUM(col2) > $m", m: 2).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name HAVING (COUNT(col1) > 1) AND (SUM(col2) > 2)) + assert_equal parsed, %(SELECT id, name FROM table_name HAVING (COUNT(col1) > 1) AND (SUM(col2) > 2)) end def test_select_limit parsed = Qx.select(:id, "name").from(:table_name).limit(10).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name LIMIT 10) + assert_equal parsed, %(SELECT id, name FROM table_name LIMIT 10) end + def test_select_offset parsed = Qx.select(:id, "name").from(:table_name).offset(10).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name OFFSET 10) + assert_equal parsed, %(SELECT id, name FROM table_name OFFSET 10) end def test_select_join - parsed = Qx.select(:id, "name").from(:table_name).join(['assoc1', 'assoc1.table_name_id=table_name.id']).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name JOIN assoc1 ON assoc1.table_name_id=table_name.id) + parsed = Qx.select(:id, "name").from(:table_name).join(["assoc1", "assoc1.table_name_id=table_name.id"]).parse + assert_equal parsed, %(SELECT id, name FROM table_name JOIN assoc1 ON assoc1.table_name_id=table_name.id) end + def test_select_add_join - parsed = Qx.select(:id, "name").from(:table_name).join('assoc1', 'assoc1.table_name_id=table_name.id') - .add_join(['assoc2', 'assoc2.table_name_id=table_name.id']).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name JOIN assoc1 ON assoc1.table_name_id=table_name.id JOIN assoc2 ON assoc2.table_name_id=table_name.id) + parsed = Qx.select(:id, "name").from(:table_name).join("assoc1", "assoc1.table_name_id=table_name.id") + .add_join(["assoc2", "assoc2.table_name_id=table_name.id"]).parse + assert_equal parsed, %(SELECT id, name FROM table_name JOIN assoc1 ON assoc1.table_name_id=table_name.id JOIN assoc2 ON assoc2.table_name_id=table_name.id) end + def test_select_left_join - parsed = Qx.select(:id, "name").from(:table_name).left_join(['assoc1', 'assoc1.table_name_id=table_name.id']).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name LEFT JOIN assoc1 ON assoc1.table_name_id=table_name.id) + parsed = Qx.select(:id, "name").from(:table_name).left_join(["assoc1", "assoc1.table_name_id=table_name.id"]).parse + assert_equal parsed, %(SELECT id, name FROM table_name LEFT JOIN assoc1 ON assoc1.table_name_id=table_name.id) end + def test_select_add_left_join - parsed = Qx.select(:id, "name").from(:table_name).left_join('assoc1', 'assoc1.table_name_id=table_name.id') - .add_left_join(['assoc2', 'assoc2.table_name_id=table_name.id']).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name LEFT JOIN assoc1 ON assoc1.table_name_id=table_name.id LEFT JOIN assoc2 ON assoc2.table_name_id=table_name.id) + parsed = Qx.select(:id, "name").from(:table_name).left_join("assoc1", "assoc1.table_name_id=table_name.id") + .add_left_join(["assoc2", "assoc2.table_name_id=table_name.id"]).parse + assert_equal parsed, %(SELECT id, name FROM table_name LEFT JOIN assoc1 ON assoc1.table_name_id=table_name.id LEFT JOIN assoc2 ON assoc2.table_name_id=table_name.id) end def test_select_where_subquery parsed = Qx.select(:id, "name").from(:table_name).where("id IN ($ids)", ids: Qx.select("id").from("assoc")).parse - assert_equal parsed, %Q(SELECT id, name FROM table_name WHERE (id IN (SELECT id FROM assoc))) + assert_equal parsed, %(SELECT id, name FROM table_name WHERE (id IN (SELECT id FROM assoc))) end def test_select_join_subquery parsed = Qx.select(:id).from(:table).join([Qx.select(:id).from(:assoc).as(:assoc), "assoc.table_id=table.id"]).parse - assert_equal parsed, %Q(SELECT id FROM table JOIN (SELECT id FROM assoc) AS "assoc" ON assoc.table_id=table.id) + assert_equal parsed, %(SELECT id FROM table JOIN (SELECT id FROM assoc) AS "assoc" ON assoc.table_id=table.id) end def test_select_from_subquery parsed = Qx.select(:id).from(Qx.select(:id).from(:table).as(:table)).parse - assert_equal parsed, %Q(SELECT id FROM (SELECT id FROM table) AS "table") + assert_equal parsed, %(SELECT id FROM (SELECT id FROM table) AS "table") end def test_select_integration parsed = Qx.select(:id) .from(:table) - .join([Qx.select(:id).from(:assoc).as(:assoc), 'assoc.table_id=table.id']) - .left_join(['lefty', 'lefty.table_id=table.id']) - .where('x = $n', n: 1) - .and_where('y = $n', n: 1) + .join([Qx.select(:id).from(:assoc).as(:assoc), "assoc.table_id=table.id"]) + .left_join(["lefty", "lefty.table_id=table.id"]) + .where("x = $n", n: 1) + .and_where("y = $n", n: 1) .group_by(:x) .order_by(:y) - .having('COUNT(x) > $n', n: 1) - .and_having('COUNT(y) > $n', n: 1) + .having("COUNT(x) > $n", n: 1) + .and_having("COUNT(y) > $n", n: 1) .limit(10) .offset(10) .parse - assert_equal parsed, %Q(SELECT id FROM table JOIN (SELECT id FROM assoc) AS "assoc" ON assoc.table_id=table.id LEFT JOIN lefty ON lefty.table_id=table.id WHERE (x = 1) AND (y = 1) GROUP BY x HAVING (COUNT(x) > 1) AND (COUNT(y) > 1) ORDER BY y LIMIT 10 OFFSET 10) + assert_equal parsed, %(SELECT id FROM table JOIN (SELECT id FROM assoc) AS "assoc" ON assoc.table_id=table.id LEFT JOIN lefty ON lefty.table_id=table.id WHERE (x = 1) AND (y = 1) GROUP BY x HAVING (COUNT(x) > 1) AND (COUNT(y) > 1) ORDER BY y LIMIT 10 OFFSET 10) end def test_insert_into_values_hash parsed = Qx.insert_into(:table_name).values(x: 1).parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x") VALUES (1)) + assert_equal parsed, %(INSERT INTO "table_name" ("x") VALUES (1)) end + def test_insert_into_values_hash_array parsed = Qx.insert_into(:table_name).values([{x: 1}, {x: 2}]).parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x") VALUES (1), (2)) + assert_equal parsed, %(INSERT INTO "table_name" ("x") VALUES (1), (2)) end + def test_insert_into_values_csv_style - parsed = Qx.insert_into(:table_name).values([['x'], [1], [2]]).parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x") VALUES (1), (2)) + parsed = Qx.insert_into(:table_name).values([["x"], [1], [2]]).parse + assert_equal parsed, %(INSERT INTO "table_name" ("x") VALUES (1), (2)) end + def test_insert_into_values_common_values - parsed = Qx.insert_into(:table_name).values([{x: 'bye'}, {x: 'hi'}]).common_values(z: 1).parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x", "z") VALUES ($Q$bye$Q$, 1), ($Q$hi$Q$, 1)) + parsed = Qx.insert_into(:table_name).values([{x: "bye"}, {x: "hi"}]).common_values(z: 1).parse + assert_equal parsed, %(INSERT INTO "table_name" ("x", "z") VALUES ($Q$bye$Q$, 1), ($Q$hi$Q$, 1)) end + def test_insert_into_values_timestamps parsed = Qx.insert_into(:table_name).values(x: 1).ts.parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x", created_at, updated_at) VALUES (1, '#{Time.now.utc}', '#{Time.now.utc}')) + assert_equal parsed, %(INSERT INTO "table_name" ("x", created_at, updated_at) VALUES (1, '#{Time.now.utc}', '#{Time.now.utc}')) end + def test_insert_into_values_returning - parsed = Qx.insert_into(:table_name).values(x: 1).returning('*').parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x") VALUES (1) RETURNING *) + parsed = Qx.insert_into(:table_name).values(x: 1).returning("*").parse + assert_equal parsed, %(INSERT INTO "table_name" ("x") VALUES (1) RETURNING *) end + def test_insert_into_select - parsed = Qx.insert_into(:table_name, ['hi']).select('hi').from(:table2).where("x=y").parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("hi") SELECT hi FROM table2 WHERE (x=y)) + parsed = Qx.insert_into(:table_name, ["hi"]).select("hi").from(:table2).where("x=y").parse + assert_equal parsed, %(INSERT INTO "table_name" ("hi") SELECT hi FROM table2 WHERE (x=y)) end def test_update_set parsed = Qx.update(:table_name).set(x: 1).where("y = 2").parse - assert_equal parsed, %Q(UPDATE "table_name" SET "x" = 1 WHERE (y = 2)) + assert_equal parsed, %(UPDATE "table_name" SET "x" = 1 WHERE (y = 2)) end + def test_update_timestamps now = Time.now.utc parsed = Qx.update(:table_name).set(x: 1).where("y = 2").timestamps.parse - assert_equal parsed, %Q(UPDATE "table_name" SET "x" = 1, updated_at = '#{now}' WHERE (y = 2)) + assert_equal parsed, %(UPDATE "table_name" SET "x" = 1, updated_at = '#{now}' WHERE (y = 2)) end def test_update_on_conflict Qx.update(:table_name).set(x: 1).where("y = 2").on_conflict(:nothing).parse - assert_equal parsed, %Q(UPDATE "table_name" SET "x" = 1 WHERE (y = 2) ON CONFLICT DO NOTHING) + assert_equal parsed, %(UPDATE "table_name" SET "x" = 1 WHERE (y = 2) ON CONFLICT DO NOTHING) end def test_insert_timestamps now = Time.now.utc parsed = Qx.insert_into(:table_name).values({x: 1}).ts.parse - assert_equal parsed, %Q(INSERT INTO "table_name" ("x", created_at, updated_at) VALUES (1, '#{now}', '#{now}')) + assert_equal parsed, %(INSERT INTO "table_name" ("x", created_at, updated_at) VALUES (1, '#{now}', '#{now}')) end def test_delete_from parsed = Qx.delete_from(:table_name).where(x: 1).parse - assert_equal parsed, %Q(DELETE FROM "table_name" WHERE ("x" IN (1))) + assert_equal parsed, %(DELETE FROM "table_name" WHERE ("x" IN (1))) end def test_pagination parsed = Qx.select(:x).from(:y).paginate(4, 30).parse - assert_equal parsed, %Q(SELECT x FROM y LIMIT 30 OFFSET 90) + assert_equal parsed, %(SELECT x FROM y LIMIT 30 OFFSET 90) end def test_execute_string - result = Qx.execute("SELECT * FROM (VALUES ($x)) AS t", x: 'x') - assert_equal result, [{'column1' => 'x'}] + result = Qx.execute("SELECT * FROM (VALUES ($x)) AS t", x: "x") + assert_equal result, [{"column1" => "x"}] end + def test_execute_format_csv - result = Qx.execute("SELECT * FROM (VALUES ($x)) AS t", {x: 'x'}, {format: 'csv'}) - assert_equal result, [['column1'], ['x']] + result = Qx.execute("SELECT * FROM (VALUES ($x)) AS t", {x: "x"}, {format: "csv"}) + assert_equal result, [["column1"], ["x"]] end + def test_execute_on_instances - result = Qx.insert_into(:users).values(id: 1, email: 'uzr@example.com').execute + Qx.insert_into(:users).values(id: 1, email: "uzr@example.com").execute result = Qx.execute(Qx.select("*").from(:users).limit(1)) - assert_equal result, [{'id' => 1, 'email' => 'uzr@example.com'}] + assert_equal result, [{"id" => 1, "email" => "uzr@example.com"}] Qx.delete_from(:users).where(id: 1).execute end def test_explain parsed = Qx.select("*").from("table_name").explain.parse - assert_equal parsed, %Q(EXPLAIN SELECT * FROM table_name) + assert_equal parsed, %(EXPLAIN SELECT * FROM table_name) end # Manually test this one for now def test_pp_select - pp = Qx.select("id, name").from("table_name").where(status: 'active').and_where(id: Qx.select("id").from("roles").where(name: "admin")).pp + pp = Qx.select("id, name").from("table_name").where(status: "active").and_where(id: Qx.select("id").from("roles").where(name: "admin")).pp pp2 = Qx.insert_into(:table_name).values([x: 1, y: 2]).pp pp3 = Qx.update(:table_name).set(x: 1, y: 2).where(z: 1, a: 22).pp pp_delete = Qx.delete_from(:table_name).where(id: 123).pp @@ -233,7 +251,7 @@ def test_pp_select def test_to_json parsed = Qx.select(:id).from(:users).to_json(:t).parse - assert_equal parsed, %Q(SELECT array_to_json(array_agg(row_to_json(t))) FROM (SELECT id FROM users) AS "t") + assert_equal parsed, %(SELECT array_to_json(array_agg(row_to_json(t))) FROM (SELECT id FROM users) AS "t") end def test_to_json_nested @@ -252,12 +270,12 @@ def test_to_json_nested end def test_copy_csv_execution - data = {'id' => '1', 'email' => 'uzr@example.com'} - filename = '/tmp/qx-test.csv' + data = {"id" => "1", "email" => "uzr@example.com"} + filename = "/tmp/qx-test.csv" Qx.insert_into(:users).values(data).ex - copy = Qx.select("*").from("users").execute(copy_csv: filename) - contents = File.open(filename, 'r').read - csv_data = contents.split("\n").map{|l| l.split(",")} + Qx.select("*").from("users").execute(copy_csv: filename) + contents = File.read(filename) + csv_data = contents.split("\n").map { |l| l.split(",") } headers = csv_data.first row = csv_data.last assert_equal data.keys, headers @@ -266,10 +284,7 @@ def test_copy_csv_execution def test_remove_clause expr = Qx.select("*").from("table").limit(1) - expr = expr.remove_clause('limit') + expr = expr.remove_clause("limit") assert_equal "SELECT * FROM table", expr.parse end - - - end diff --git a/lib/generators/ts/declaration/declaration_generator.rb b/lib/generators/ts/declaration/declaration_generator.rb index 3c1a9e09c..c2bc199c4 100644 --- a/lib/generators/ts/declaration/declaration_generator.rb +++ b/lib/generators/ts/declaration/declaration_generator.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Ts::DeclarationGenerator < Rails::Generators::NamedBase - source_root File.expand_path('../templates', __FILE__) + source_root File.expand_path("../templates", __FILE__) def copy_template - template 'template.d.ts.erb', File.join("types", name, 'index.d.ts') + template "template.d.ts.erb", File.join("types", name, "index.d.ts") end end diff --git a/lib/tasks/health_report.rake b/lib/tasks/health_report.rake index daa1a9103..57aaabba2 100644 --- a/lib/tasks/health_report.rake +++ b/lib/tasks/health_report.rake @@ -2,7 +2,7 @@ desc "For sending an activity report email of what has been happening on the system" # Clear old activerecord sessions tables daily -task :send_health_report => :environment do +task send_health_report: :environment do GenericMailer.admin_notice({ body: HealthReport.format_data(HealthReport.query_data), subject: "CommitChange activity report #{Format::Date.to_readable(Time.now)}" diff --git a/lib/tasks/js.rake b/lib/tasks/js.rake index acf8c9c2c..a8713a57d 100644 --- a/lib/tasks/js.rake +++ b/lib/tasks/js.rake @@ -2,16 +2,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -desc 'Javascript related tasks' +desc "Javascript related tasks" namespace :js do - desc 'generate all the pre-build Javascript' - task generate: ['js:routes:typescript', 'i18n:js:export'] - namespace :routes do - desc 'delete generated route files' - task clean: :environment do - js_dir = Rails.root.join('app/javascript') - FileUtils.rm_f js_dir.join('routes.js') - FileUtils.rm_f js_dir.join('routes.d.ts') - end - end + desc "generate all the pre-build Javascript" + task generate: ["js:routes:typescript", "i18n:js:export"] + namespace :routes do + desc "delete generated route files" + task clean: :environment do + js_dir = Rails.root.join("app/javascript") + FileUtils.rm_f js_dir.join("routes.js") + FileUtils.rm_f js_dir.join("routes.d.ts") + end + end end diff --git a/lib/tasks/js_routes.rake b/lib/tasks/js_routes.rake index b216ff57d..524ad0711 100644 --- a/lib/tasks/js_routes.rake +++ b/lib/tasks/js_routes.rake @@ -7,7 +7,7 @@ # adds support for generating js routes as part of the assets:precompile task namespace :assets do - task precompile: 'js:routes:typescript' + task precompile: "js:routes:typescript" end # rubocop:enable Rake/Desc diff --git a/lib/tasks/scheduler.rake b/lib/tasks/scheduler.rake index a0884b124..c041401c7 100644 --- a/lib/tasks/scheduler.rake +++ b/lib/tasks/scheduler.rake @@ -10,12 +10,10 @@ task :heroku_scheduled_job, [:name] => :environment do |t, args| results = "" enum.each do |lamb| - begin - result = lamb.call - results += "Success: #{result}\n" - rescue Exception => e - results += "Failure: #{e}\n" - end + result = lamb.call + results += "Success: #{result}\n" + rescue Exception => e + results += "Failure: #{e}\n" end GenericMailer.delay.admin_notice({ subject: "Scheduled job results on CommitChange for '#{job_name}'", diff --git a/lib/tasks/seed.rake b/lib/tasks/seed.rake index 19458b168..8a419a15c 100644 --- a/lib/tasks/seed.rake +++ b/lib/tasks/seed.rake @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later namespace :seed do - - task :np => :environment do - ActiveRecord::Base.transaction do - supers = Role.super_admins.includes(:user).map{|r| r.user} - n = Nonprofit.register(supers.last, name: "Testify #{rand(0..100)}", city: 'Albuquerque', state_code: 'NM') - n.vetted = true - n.create_billing_subscription({billing_plan: BillingPlan.last}) - n.save! - supers.each{|user| user.roles.create(name: :nonprofit_admin, host: n)} - puts "New test nonprofit id: #{n.id}" - end - end + task np: :environment do + ActiveRecord::Base.transaction do + supers = Role.super_admins.includes(:user).map { |r| r.user } + n = Nonprofit.register(supers.last, name: "Testify #{rand(0..100)}", city: "Albuquerque", state_code: "NM") + n.vetted = true + n.create_billing_subscription({billing_plan: BillingPlan.last}) + n.save! + supers.each { |user| user.roles.create(name: :nonprofit_admin, host: n) } + puts "New test nonprofit id: #{n.id}" + end + end end diff --git a/lib/tasks/settings.rake b/lib/tasks/settings.rake index fcb1fbb00..8dbe3753c 100644 --- a/lib/tasks/settings.rake +++ b/lib/tasks/settings.rake @@ -2,36 +2,33 @@ namespace :settings do task :environment do - require File.expand_path('../../config/environment.rb', File.dirname(__FILE__)) + require File.expand_path("../../config/environment.rb", File.dirname(__FILE__)) end desc "show settings" - task :show => :environment do - require 'pp' + task show: :environment do + require "pp" pp Settings.to_hash end - task :generate_json => :environment do - - cdn_url= URI(Settings.cdn.url) + task generate_json: :environment do + cdn_url = URI(Settings.cdn.url) cdn_url = cdn_url.to_s - if (Settings.button_config&.url) - cdn_url= URI(Settings.button_config.url).to_s + if Settings.button_config&.url + cdn_url = URI(Settings.button_config.url).to_s end - c = {button:{url:cdn_url,css:"#{cdn_url}/css/donate-button.v2.css"}} - open(File.expand_path('config/settings.json', Rails.root), 'w') do |f| + c = {button: {url: cdn_url, css: "#{cdn_url}/css/donate-button.v2.css"}} + open(File.expand_path("config/settings.json", Rails.root), "w") do |f| f.write(c.to_json) end end - task :combine_translations => 'i18n:js:export' do - js_root = File.expand_path('public/javascripts', Rails.root) - #i18n = File.read(File.join(js_root, 'i18n.js')) - translations = File.read(File.join(js_root, 'translations.js')) - open(File.join(js_root, '_final.js'), 'w') do |f| + task combine_translations: "i18n:js:export" do + js_root = File.expand_path("public/javascripts", Rails.root) + # i18n = File.read(File.join(js_root, 'i18n.js')) + translations = File.read(File.join(js_root, "translations.js")) + open(File.join(js_root, "_final.js"), "w") do |f| f.write("const I18n = require('i18n-js');\n" + translations + "\n window.I18n = I18n") end end - end - diff --git a/spec/controllers/aws_presigned_posts_spec.rb b/spec/controllers/aws_presigned_posts_spec.rb index 51e71c04e..c1d87f503 100644 --- a/spec/controllers/aws_presigned_posts_spec.rb +++ b/spec/controllers/aws_presigned_posts_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe AwsPresignedPostsController, :type => :controller do - describe 'authorization' do +describe AwsPresignedPostsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do + describe "rejects unauthorized users" do + describe "create" do include_context :open_to_registered, :post, :create end end end -end \ No newline at end of file +end diff --git a/spec/controllers/billing_subscriptions_spec.rb b/spec/controllers/billing_subscriptions_spec.rb index f11926e84..7e5b7392c 100644 --- a/spec/controllers/billing_subscriptions_spec.rb +++ b/spec/controllers/billing_subscriptions_spec.rb @@ -1,17 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe BillingSubscriptionsController, :type => :controller do - describe 'authorization' do +describe BillingSubscriptionsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'cancel' do - include_context :open_to_np_admin, :post, :cancel, nonprofit_id: :__our_np + describe "cancel" do + include_context :open_to_np_admin, :post, :cancel, nonprofit_id: :__our_np end - describe 'cancellation' do - include_context :open_to_np_admin, :get, :cancellation, nonprofit_id: :__our_np, without_json_view: true + describe "cancellation" do + include_context :open_to_np_admin, :get, :cancellation, nonprofit_id: :__our_np, without_json_view: true end end -end \ No newline at end of file +end diff --git a/spec/controllers/campaign_gift_options_spec.rb b/spec/controllers/campaign_gift_options_spec.rb index 4dcc4c570..aa59558bb 100644 --- a/spec/controllers/campaign_gift_options_spec.rb +++ b/spec/controllers/campaign_gift_options_spec.rb @@ -1,35 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe CampaignGiftOptionsController, :type => :controller do - describe 'authorization' do +describe CampaignGiftOptionsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'reject unauthorized' do - describe 'create' do + describe "reject unauthorized" do + describe "create" do include_context :open_to_campaign_editor, :post, :create, nonprofit_id: :__our_np, campaign_id: :__our_campaign end - describe 'update' do + describe "update" do include_context :open_to_campaign_editor, :put, :update, nonprofit_id: :__our_np, campaign_id: :__our_campaign, id: 1111 end - describe 'destroy' do + describe "destroy" do include_context :open_to_campaign_editor, :delete, :destroy, nonprofit_id: :__our_np, campaign_id: :__our_campaign, id: 1111 end - describe 'update_order' do + describe "update_order" do include_context :open_to_campaign_editor, :put, :update_order, nonprofit_id: :__our_np, campaign_id: :__our_campaign, id: 1111 end end - describe 'accept all' do - describe 'index' do + describe "accept all" do + describe "index" do include_context :open_to_all, :get, :index, nonprofit_id: :__our_np, campaign_id: :__our_campaign end - describe 'show' do - include_context :open_to_all, :get, :show, nonprofit_id: :__our_np, campaign_id: :__our_campaign, id: '1' + describe "show" do + include_context :open_to_all, :get, :show, nonprofit_id: :__our_np, campaign_id: :__our_campaign, id: "1" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/campaign_gifts_spec.rb b/spec/controllers/campaign_gifts_spec.rb index 06f3f599f..a6a70f242 100644 --- a/spec/controllers/campaign_gifts_spec.rb +++ b/spec/controllers/campaign_gifts_spec.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe CampaignGiftsController, :type => :controller do - describe 'authorization' do +describe CampaignGiftsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'accept all' do - describe 'create' do + describe "accept all" do + describe "create" do include_context :open_to_all, :post, :create, nonprofit_id: :__our_np, campaign_id: :__our_campaign end end end -end \ No newline at end of file +end diff --git a/spec/controllers/campaigns/campaign_gift_options_spec.rb b/spec/controllers/campaigns/campaign_gift_options_spec.rb index 9627d7fca..3477b1784 100644 --- a/spec/controllers/campaigns/campaign_gift_options_spec.rb +++ b/spec/controllers/campaigns/campaign_gift_options_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Campaigns::CampaignGiftOptionsController, :type => :controller do - describe 'authorization' do +describe Campaigns::CampaignGiftOptionsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'reject unauthorized users' do - describe 'index' do - include_context :open_to_campaign_editor, :get, :index, nonprofit_id: :__our_np, campaign_id: :__our_campaign + describe "reject unauthorized users" do + describe "index" do + include_context :open_to_campaign_editor, :get, :index, nonprofit_id: :__our_np, campaign_id: :__our_campaign end end end -end \ No newline at end of file +end diff --git a/spec/controllers/campaigns/donations_spec.rb b/spec/controllers/campaigns/donations_spec.rb index 11c403364..c83319fdd 100644 --- a/spec/controllers/campaigns/donations_spec.rb +++ b/spec/controllers/campaigns/donations_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Campaigns::DonationsController, :type => :controller do - describe 'authorization' do +describe Campaigns::DonationsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'reject unauthorized' do - describe 'index' do - include_context :open_to_campaign_editor, :get, :index, nonprofit_id: :__our_np, campaign_id: :__our_campaign + describe "reject unauthorized" do + describe "index" do + include_context :open_to_campaign_editor, :get, :index, nonprofit_id: :__our_np, campaign_id: :__our_campaign end end end -end \ No newline at end of file +end diff --git a/spec/controllers/campaigns/supporters_spec.rb b/spec/controllers/campaigns/supporters_spec.rb index d452279ae..794f62c57 100644 --- a/spec/controllers/campaigns/supporters_spec.rb +++ b/spec/controllers/campaigns/supporters_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Campaigns::SupportersController, :type => :controller do - describe 'authorization' do +describe Campaigns::SupportersController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'reject unauthorized' do - describe 'index' do + describe "reject unauthorized" do + describe "index" do include_context :open_to_campaign_editor, :get, :index, nonprofit_id: :__our_np, campaign_id: :__our_campaign, without_json_view: true end end end -end \ No newline at end of file +end diff --git a/spec/controllers/campaigns_spec.rb b/spec/controllers/campaigns_spec.rb index 243cfd562..c476ba2d9 100644 --- a/spec/controllers/campaigns_spec.rb +++ b/spec/controllers/campaigns_spec.rb @@ -1,59 +1,59 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe CampaignsController, :type => :controller do - describe 'authorization' do +describe CampaignsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do + describe "rejects unauthorized users" do + describe "create" do include_context :open_to_confirmed_users, :post, :create, nonprofit_id: :__our_np end - describe 'name_and_id' do + describe "name_and_id" do include_context :open_to_confirmed_users, :get, :name_and_id, nonprofit_id: :__our_np end - describe 'duplicate' do + describe "duplicate" do include_context :open_to_confirmed_users, :post, :duplicate, nonprofit_id: :__our_np, id: :__our_campaign end - describe 'update' do + describe "update" do include_context :open_to_campaign_editor, :put, :update, nonprofit_id: :__our_np, id: :__our_campaign end - describe 'soft_delete' do + describe "soft_delete" do include_context :open_to_campaign_editor, :delete, :soft_delete, nonprofit_id: :__our_np, id: :__our_campaign end end - describe 'open to all' do - describe 'index' do + describe "open to all" do + describe "index" do include_context :open_to_all, :get, :index, nonprofit_id: :__our_np, without_json_view: true end - describe 'show' do + describe "show" do include_context :open_to_all, :get, :show, nonprofit_id: :__our_np, id: :__our_campaign, without_json_view: true end - describe 'activities' do + describe "activities" do include_context :open_to_all, :get, :activities, nonprofit_id: :__our_np, id: :__our_campaign end - describe 'metrics' do + describe "metrics" do include_context :open_to_all, :get, :metrics, nonprofit_id: :__our_np, id: :__our_campaign end - describe 'timeline' do + describe "timeline" do include_context :open_to_all, :get, :timeline, nonprofit_id: :__our_np, id: :__our_campaign end - describe 'totals' do + describe "totals" do include_context :open_to_all, :get, :totals, nonprofit_id: :__our_np, id: :__our_campaign end - describe 'peer_to_peer' do + describe "peer_to_peer" do include_context :open_to_all, :get, :peer_to_peer, nonprofit_id: :__our_np, without_json_view: true end end end -end \ No newline at end of file +end diff --git a/spec/controllers/cards_spec.rb b/spec/controllers/cards_spec.rb index ab143f638..29ab51e5e 100644 --- a/spec/controllers/cards_spec.rb +++ b/spec/controllers/cards_spec.rb @@ -1,32 +1,32 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe CardsController, :type => :controller do - describe 'authorization' do +describe CardsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'accept all' do - describe 'create' do - include_context :open_to_all, :post, :create, nonprofit_id: :__our_np + describe "accept all" do + describe "create" do + include_context :open_to_all, :post, :create, nonprofit_id: :__our_np end end end - it {is_expected.to rescue_from(::Recaptcha::RecaptchaError).with(:handle_recaptcha_failure)} + it { is_expected.to rescue_from(::Recaptcha::RecaptchaError).with(:handle_recaptcha_failure) } - it {is_expected.to use_before_action(:verify_via_recaptcha!)} - - describe '#create' do - context 'recaptcha' do - it 'handles verification failure' do + it { is_expected.to use_before_action(:verify_via_recaptcha!) } + + describe "#create" do + context "recaptcha" do + it "handles verification failure" do expect(controller).to receive(:verify_recaptcha).and_return(false) expect { - post :create, params: {:recaptcha_response_field => "response", 'g-recaptcha-response-data' => 'string', type: :json} - }.to change { RecaptchaRejection.count}.by(1) - + post :create, params: {:recaptcha_response_field => "response", "g-recaptcha-response-data" => "string", :type => :json} + }.to change { RecaptchaRejection.count }.by(1) + expect(response).to have_http_status(:unprocessable_entity) expect(response.body).to include "5X4J" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/concerns/jbuilder_expansions_spec.rb b/spec/controllers/concerns/jbuilder_expansions_spec.rb index 7d4b72b8b..0524affaf 100644 --- a/spec/controllers/concerns/jbuilder_expansions_spec.rb +++ b/spec/controllers/concerns/jbuilder_expansions_spec.rb @@ -2,341 +2,327 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' - -describe Controllers::ApiNew::JbuilderExpansions do - - - - describe "#handle_expansion" do - def convert_to_json(tree) - JSON::parse(tree) - end - let(:simple_object) { - create(:simple_object_with_friends_and_parent) - } - context 'when shrunk' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: {simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new - })) - } - - it { - is_expected.to include("parent" => simple_object.parent.houid) - } - end - - context 'when expanded' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: { - simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('parent') - })) - } - - it { - is_expected.to include("parent" => { - 'id' => simple_object.parent.houid, - 'parent' => simple_object.parent.parent.houid, - 'friends' => [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'object' => 'simple_object', - 'nonprofit' => nil - }) - } - end - - context 'when expanded twice' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: { - simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('parent.parent') - })) - } - - it { - is_expected.to include("parent" => { - 'id' => simple_object.parent.houid, - 'parent' => { - 'id' => simple_object.parent.parent.houid, - 'parent' => nil, - 'object' => 'simple_object', - 'friends' => [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'nonprofit' => nil - }, - 'friends' => [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'object' => 'simple_object', - 'nonprofit' => nil - }) - } - end - - end - - describe '#handle_array_expansion/#handle_item_expansion' do - def convert_to_json(tree) - JSON::parse(tree) - end - let(:simple_object) { - create(:simple_object_with_friends_and_parent) - } - context 'when shrunk' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: {simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new - })) - } - - it { - is_expected.to include("friends" => - match_array(simple_object.friends.pluck(:houid))) - } - end - - context 'when expanded' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: { - simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('friends') - })) - } - - it { - is_expected.to include("friends" => - match_array([ - { - 'id' => simple_object.friends.first.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'parent' => nil, - 'nonprofit' => nil - }, - { - 'id' => simple_object.friends.last.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'parent' => simple_object.friends.last.parent.houid, - 'nonprofit' => nil - }, - ]), - "friends_without_explicit_call" => match_array(simple_object.friends.pluck(:houid)), - 'friends_no_block_given' => match_array(simple_object.friends.pluck(:houid)), - ) - } - end - - context 'when expanded once without passing a specific value to #handle_item_expansion' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: { - simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('friends_without_explicit_call') - })) - } - - it { - is_expected.to include("friends_without_explicit_call" => - match_array([ - { - 'id' => simple_object.friends.first.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_no_block_given' => [], - 'friends_without_explicit_call' => [], - 'parent' => nil, - 'nonprofit' => nil - }, - { - 'id' => simple_object.friends.last.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_no_block_given' => [], - 'friends_without_explicit_call' => [], - 'parent' => simple_object.friends.last.parent.houid, - 'nonprofit' => nil - }, - ]), - "friends" => match_array(simple_object.friends.pluck(:houid)), - 'friends_no_block_given' => match_array(simple_object.friends.pluck(:houid)), - ) - } - end - - context 'when expanded once without no block given to #handle_array_expansion' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: { - simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('friends_no_block_given') - })) - } - - it { - is_expected.to include("friends_no_block_given" => - match_array([ - { - 'id' => simple_object.friends.first.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'parent' => nil, - 'nonprofit' => nil - }, - { - 'id' => simple_object.friends.last.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_without_explicit_call' => [], - 'friends_no_block_given' => [], - 'parent' => simple_object.friends.last.parent.houid, - 'nonprofit' => nil - }, - ]), - "friends" => match_array(simple_object.friends.pluck(:houid)), - 'friends_without_explicit_call' => match_array(simple_object.friends.pluck(:houid)) - ) - } - end - - context 'when expanded twice' do - subject { - convert_to_json(ApiNew::ApiController.render('api_new/simple_objects/show', - assigns: { - simple_object:simple_object, - __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('friends.parent') - })) - } - - it { - is_expected.to include_json("friends" => - match_array([ - { - 'id' => simple_object.friends.first.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_no_block_given' => [], - 'friends_without_explicit_call' => [], - 'parent' => nil, - 'nonprofit' => nil - }, - { - 'id' => simple_object.friends.last.houid, - 'object' => 'simple_object', - 'friends'=> [], - 'friends_no_block_given' => [], - 'friends_without_explicit_call' => [], - 'parent' => { - 'id' => simple_object.friends.last.parent.houid, - 'object' => 'simple_object', - 'friends' => [], - 'friends_no_block_given' => [], - 'friends_without_explicit_call' => [], - 'parent' => nil, - 'nonprofit' => nil - }, - 'nonprofit' => nil - - }, - ]), - "friends_without_explicit_call" => [simple_object.friends.first.houid, simple_object.friends.last.houid], - 'friends_no_block_given' => match_array(simple_object.friends.pluck(:houid)) - ) - } - end - end - - - describe '::ExpansionTree' do - def convert_to_json(expansion_request) - JSON::parse(JSON::dump(expansion_request.root_node)) - end - context 'can be empty' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new)} - - it { - is_expected.to be_empty - } - end - - context 'can have a single item' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter'))} - - it { - is_expected.to include_json(supporter: {}) - } - end - - context 'can have a multiple items at multiple levels' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter', 'transaction.subtransaction'))} - - it { - is_expected.to include_json(supporter: {}, transaction: {subtransaction: {}}) - } - end - - context 'can safely have shorter paths that dont overload longer paths' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter', 'transaction.subtransaction', 'transaction'))} - - it { - is_expected.to include_json(supporter: {}, transaction: {subtransaction: {}}) - } - end - - describe "#[]" do - context 'returns an empty ExpansionTree when no child with the given path exists' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter')['transaction'])} - - it { - is_expected.to be_empty - } - end - - context 'returns a child\'s ExpansionTree' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter', 'transaction.subtransaction')['transaction'])} - - it { - is_expected.to include_json({subtransaction: {}}) - } - - end - - context 'keeps returning empty ExpansionTrees when none are available' do - subject{ convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('transaction.subtransaction')['transaction']['subtransaction']['payments']['charge'])} - - it { - is_expected.to include_json({}) - } - - end - end - - describe '#expand?' do - subject { Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter', 'transaction.subtransaction', 'transaction') } - - it 'returns false when a path should not be expanded' do - is_expected.to_not be_expand 'nonprofit' - end - - it 'returns true when a path should be expanded' do - is_expected.to be_expand 'supporter' - end - - end - end -end \ No newline at end of file +require "rails_helper" + +describe Controllers::ApiNew::JbuilderExpansions do + describe "#handle_expansion" do + def convert_to_json(tree) + JSON.parse(tree) + end + let(:simple_object) { + create(:simple_object_with_friends_and_parent) + } + context "when shrunk" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: {simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new})) + } + + it { + is_expected.to include("parent" => simple_object.parent.houid) + } + end + + context "when expanded" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: { + simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("parent") + })) + } + + it { + is_expected.to include("parent" => { + "id" => simple_object.parent.houid, + "parent" => simple_object.parent.parent.houid, + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "object" => "simple_object", + "nonprofit" => nil + }) + } + end + + context "when expanded twice" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: { + simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("parent.parent") + })) + } + + it { + is_expected.to include("parent" => { + "id" => simple_object.parent.houid, + "parent" => { + "id" => simple_object.parent.parent.houid, + "parent" => nil, + "object" => "simple_object", + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "nonprofit" => nil + }, + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "object" => "simple_object", + "nonprofit" => nil + }) + } + end + end + + describe "#handle_array_expansion/#handle_item_expansion" do + def convert_to_json(tree) + JSON.parse(tree) + end + let(:simple_object) { + create(:simple_object_with_friends_and_parent) + } + context "when shrunk" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: {simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new})) + } + + it { + is_expected.to include("friends" => + match_array(simple_object.friends.pluck(:houid))) + } + end + + context "when expanded" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: { + simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("friends") + })) + } + + it { + is_expected.to include("friends" => + match_array([ + { + "id" => simple_object.friends.first.houid, + "object" => "simple_object", + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "parent" => nil, + "nonprofit" => nil + }, + { + "id" => simple_object.friends.last.houid, + "object" => "simple_object", + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "parent" => simple_object.friends.last.parent.houid, + "nonprofit" => nil + } + ]), + "friends_without_explicit_call" => match_array(simple_object.friends.pluck(:houid)), + "friends_no_block_given" => match_array(simple_object.friends.pluck(:houid))) + } + end + + context "when expanded once without passing a specific value to #handle_item_expansion" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: { + simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("friends_without_explicit_call") + })) + } + + it { + is_expected.to include("friends_without_explicit_call" => + match_array([ + { + "id" => simple_object.friends.first.houid, + "object" => "simple_object", + "friends" => [], + "friends_no_block_given" => [], + "friends_without_explicit_call" => [], + "parent" => nil, + "nonprofit" => nil + }, + { + "id" => simple_object.friends.last.houid, + "object" => "simple_object", + "friends" => [], + "friends_no_block_given" => [], + "friends_without_explicit_call" => [], + "parent" => simple_object.friends.last.parent.houid, + "nonprofit" => nil + } + ]), + "friends" => match_array(simple_object.friends.pluck(:houid)), + "friends_no_block_given" => match_array(simple_object.friends.pluck(:houid))) + } + end + + context "when expanded once without no block given to #handle_array_expansion" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: { + simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("friends_no_block_given") + })) + } + + it { + is_expected.to include("friends_no_block_given" => + match_array([ + { + "id" => simple_object.friends.first.houid, + "object" => "simple_object", + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "parent" => nil, + "nonprofit" => nil + }, + { + "id" => simple_object.friends.last.houid, + "object" => "simple_object", + "friends" => [], + "friends_without_explicit_call" => [], + "friends_no_block_given" => [], + "parent" => simple_object.friends.last.parent.houid, + "nonprofit" => nil + } + ]), + "friends" => match_array(simple_object.friends.pluck(:houid)), + "friends_without_explicit_call" => match_array(simple_object.friends.pluck(:houid))) + } + end + + context "when expanded twice" do + subject { + convert_to_json(ApiNew::ApiController.render("api_new/simple_objects/show", + assigns: { + simple_object: simple_object, + __expand: Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("friends.parent") + })) + } + + it { + is_expected.to include_json("friends" => + match_array([ + { + "id" => simple_object.friends.first.houid, + "object" => "simple_object", + "friends" => [], + "friends_no_block_given" => [], + "friends_without_explicit_call" => [], + "parent" => nil, + "nonprofit" => nil + }, + { + "id" => simple_object.friends.last.houid, + "object" => "simple_object", + "friends" => [], + "friends_no_block_given" => [], + "friends_without_explicit_call" => [], + "parent" => { + "id" => simple_object.friends.last.parent.houid, + "object" => "simple_object", + "friends" => [], + "friends_no_block_given" => [], + "friends_without_explicit_call" => [], + "parent" => nil, + "nonprofit" => nil + }, + "nonprofit" => nil + + } + ]), + "friends_without_explicit_call" => [simple_object.friends.first.houid, simple_object.friends.last.houid], + "friends_no_block_given" => match_array(simple_object.friends.pluck(:houid))) + } + end + end + + describe "::ExpansionTree" do + def convert_to_json(expansion_request) + JSON.parse(JSON.dump(expansion_request.root_node)) + end + context "can be empty" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new) } + + it { + is_expected.to be_empty + } + end + + context "can have a single item" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter")) } + + it { + is_expected.to include_json(supporter: {}) + } + end + + context "can have a multiple items at multiple levels" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter", "transaction.subtransaction")) } + + it { + is_expected.to include_json(supporter: {}, transaction: {subtransaction: {}}) + } + end + + context "can safely have shorter paths that dont overload longer paths" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter", "transaction.subtransaction", "transaction")) } + + it { + is_expected.to include_json(supporter: {}, transaction: {subtransaction: {}}) + } + end + + describe "#[]" do + context "returns an empty ExpansionTree when no child with the given path exists" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter")["transaction"]) } + + it { + is_expected.to be_empty + } + end + + context "returns a child's ExpansionTree" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter", "transaction.subtransaction")["transaction"]) } + + it { + is_expected.to include_json({subtransaction: {}}) + } + end + + context "keeps returning empty ExpansionTrees when none are available" do + subject { convert_to_json(Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("transaction.subtransaction")["transaction"]["subtransaction"]["payments"]["charge"]) } + + it { + is_expected.to include_json({}) + } + end + end + + describe "#expand?" do + subject { Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter", "transaction.subtransaction", "transaction") } + + it "returns false when a path should not be expanded" do + is_expected.to_not be_expand "nonprofit" + end + + it "returns true when a path should be expanded" do + is_expected.to be_expand "supporter" + end + end + end +end diff --git a/spec/controllers/concerns/transaction/current_spec.rb b/spec/controllers/concerns/transaction/current_spec.rb index 3276a4c1d..b955a056c 100644 --- a/spec/controllers/concerns/transaction/current_spec.rb +++ b/spec/controllers/concerns/transaction/current_spec.rb @@ -2,34 +2,34 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" describe Controllers::ApiNew::Transaction::Current, type: :controller do - let(:transaction) { create(:transaction_with_legacy_donation) } - let(:nonprofit) { transaction.nonprofit } + let(:transaction) { create(:transaction_with_legacy_donation) } + let(:nonprofit) { transaction.nonprofit } - controller(ApiNew::ApiController) do - include Controllers::ApiNew::Transaction::Current + controller(ApiNew::ApiController) do + include Controllers::ApiNew::Transaction::Current - def index - render json: { - transaction: current_transaction.id - } - end - end + def index + render json: { + transaction: current_transaction.id + } + end + end - it 'gets transaction if found' do - get :index, params: { nonprofit_id: nonprofit.houid, id: transaction.houid } - expect(JSON.parse(response.body)).to eq( - { - 'transaction' => transaction.id - } - ) - end + it "gets transaction if found" do + get :index, params: {nonprofit_id: nonprofit.houid, id: transaction.houid} + expect(JSON.parse(response.body)).to eq( + { + "transaction" => transaction.id + } + ) + end - it 'throw RecordNotFound if not found' do - expect do - get :index, params: { nonprofit_id: nonprofit.houid, id: 124_124_905 } - end.to raise_error(ActiveRecord::RecordNotFound) - end + it "throw RecordNotFound if not found" do + expect do + get :index, params: {nonprofit_id: nonprofit.houid, id: 124_124_905} + end.to raise_error(ActiveRecord::RecordNotFound) + end end diff --git a/spec/controllers/direct_debit_details_spec.rb b/spec/controllers/direct_debit_details_spec.rb index 44f290607..97a33779f 100644 --- a/spec/controllers/direct_debit_details_spec.rb +++ b/spec/controllers/direct_debit_details_spec.rb @@ -1,16 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe DirectDebitDetailsController, :type => :controller do - describe 'authorization' do +describe DirectDebitDetailsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'open to all' do - describe 'create' do - include_context :open_to_all, :post, :create, nonprofit_id: :__our_np + describe "open to all" do + describe "create" do + include_context :open_to_all, :post, :create, nonprofit_id: :__our_np end - - end end -end \ No newline at end of file +end diff --git a/spec/controllers/email_settings_spec.rb b/spec/controllers/email_settings_spec.rb index 9b7c49ddc..a0168d8da 100644 --- a/spec/controllers/email_settings_spec.rb +++ b/spec/controllers/email_settings_spec.rb @@ -1,21 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe EmailSettingsController, :type => :controller do - describe 'authorization' do +describe EmailSettingsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do - include_context :open_to_np_associate, :post, :create, nonprofit_id: :__our_np + describe "rejects unauthorized users" do + describe "create" do + include_context :open_to_np_associate, :post, :create, nonprofit_id: :__our_np end - describe 'index' do - include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np + describe "index" do + include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np end - end - - end -end \ No newline at end of file +end diff --git a/spec/controllers/emails_spec.rb b/spec/controllers/emails_spec.rb index 26d1eb404..7d272abce 100644 --- a/spec/controllers/emails_spec.rb +++ b/spec/controllers/emails_spec.rb @@ -1,16 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe EmailsController, :type => :controller do - describe 'authorization' do +describe EmailsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do + describe "rejects unauthorized users" do + describe "create" do include_context :open_to_registered, :post, :create end - - end end -end \ No newline at end of file +end diff --git a/spec/controllers/event_discounts_spec.rb b/spec/controllers/event_discounts_spec.rb index 030bfc107..f32a955a1 100644 --- a/spec/controllers/event_discounts_spec.rb +++ b/spec/controllers/event_discounts_spec.rb @@ -1,28 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe EventDiscountsController, :type => :controller do - describe 'authorization' do +describe EventDiscountsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do + describe "rejects unauthorized users" do + describe "create" do include_context :open_to_event_editor, :post, :create, nonprofit_id: :__our_np, event_id: :__our_event, with_status: 200 end - describe 'update' do - include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, event_id: :__our_event, id: '2', with_status: 200 + describe "update" do + include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, event_id: :__our_event, id: "2", with_status: 200 end - describe 'destroy' do - include_context :open_to_event_editor, :delete, :destroy, nonprofit_id: :__our_np, event_id: :__our_event, id: '2', with_status: 200 + describe "destroy" do + include_context :open_to_event_editor, :delete, :destroy, nonprofit_id: :__our_np, event_id: :__our_event, id: "2", with_status: 200 end end - describe 'open to all' do - describe 'index' do - include_context :open_to_all, :get, :index, nonprofit_id: :__our_np, event_id: :__our_event, id: '2' + describe "open to all" do + describe "index" do + include_context :open_to_all, :get, :index, nonprofit_id: :__our_np, event_id: :__our_event, id: "2" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/events_spec.rb b/spec/controllers/events_spec.rb index 23d4dc039..8a219210b 100644 --- a/spec/controllers/events_spec.rb +++ b/spec/controllers/events_spec.rb @@ -1,50 +1,49 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe EventsController, :type => :controller do - describe 'authorization' do +describe EventsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'create' do + describe "create" do include_context :open_to_event_editor, :post, :create, nonprofit_id: :__our_np, id: :__our_event end - describe 'update' do + describe "update" do include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, id: :__our_event end - describe 'duplicate' do + describe "duplicate" do include_context :open_to_event_editor, :post, :duplicate, nonprofit_id: :__our_np, id: :__our_event end - describe 'soft_delete' do + describe "soft_delete" do include_context :open_to_event_editor, :delete, :soft_delete, nonprofit_id: :__our_np, event_id: :__our_event end - describe 'stats' do + describe "stats" do include_context :open_to_event_editor, :get, :stats, nonprofit_id: :__our_np, id: :__our_event, without_json_view: true end - describe 'name_and_id' do + describe "name_and_id" do include_context :open_to_np_associate, :get, :name_and_id, nonprofit_id: :__our_np, with_status: 200 end end - describe 'open to all' do - describe 'index' do + describe "open to all" do + describe "index" do include_context :open_to_all, :get, :index, nonprofit_id: :__our_np, without_json_view: true end - describe 'listings' do + describe "listings" do include_context :open_to_all, :get, :listings, nonprofit_id: :__our_np end - describe 'show' do + describe "show" do include_context :open_to_all, :get, :show, nonprofit_id: :__our_np, id: :__our_event, without_json_view: true end - describe 'activities' do + describe "activities" do include_context :open_to_all, :get, :activities, nonprofit_id: :__our_np, id: :__our_event end - describe 'metrics' do + describe "metrics" do include_context :open_to_all, :get, :metrics, nonprofit_id: :__our_np, id: :__our_event end end - -end \ No newline at end of file +end diff --git a/spec/controllers/front_spec.rb b/spec/controllers/front_spec.rb index 32f8dc1af..8927bdbd2 100644 --- a/spec/controllers/front_spec.rb +++ b/spec/controllers/front_spec.rb @@ -1,42 +1,41 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe FrontController, :type => :controller do - describe 'authorization' do +describe FrontController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'accept all' do - describe 'index' do - include_context :open_to_all, :get, :index + describe "accept all" do + describe "index" do + include_context :open_to_all, :get, :index end end end - it 'index redirects to onboard with no non-profits' do - get( :index) + it "index redirects to onboard with no non-profits" do + get(:index) expect(response).to redirect_to onboard_url end - describe 'have nonprofit info' do + describe "have nonprofit info" do include_context :shared_user_context - it 'redirect to nonprofit admin' do + it "redirect to nonprofit admin" do sign_in user_as_np_admin get(:index) expect(response).to redirect_to "/#{nonprofit.state_code_slug}/#{nonprofit.city_slug}/#{nonprofit.slug}/dashboard" end - it 'redirect to nonprofit admin' do + it "redirect to nonprofit admin" do sign_in user_as_np_associate get(:index) expect(response).to redirect_to "/#{nonprofit.state_code_slug}/#{nonprofit.city_slug}/#{nonprofit.slug}/dashboard" end - it 'redirect to general user' do + it "redirect to general user" do nonprofit unauth_user.create_profile sign_in unauth_user get(:index) expect(response).to redirect_to profile_url(unauth_user.profile.id) end - end -end \ No newline at end of file +end diff --git a/spec/controllers/image_attachments_spec.rb b/spec/controllers/image_attachments_spec.rb index c38ec1519..49789a9dc 100644 --- a/spec/controllers/image_attachments_spec.rb +++ b/spec/controllers/image_attachments_spec.rb @@ -1,18 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe ImageAttachmentsController, :type => :controller do - describe 'authorization' do +describe ImageAttachmentsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do + describe "rejects unauthorized users" do + describe "create" do include_context :open_to_confirmed_users, :post, :create end - describe 'remove' do + describe "remove" do include_context :open_to_confirmed_users, :post, :remove end end end -end \ No newline at end of file +end diff --git a/spec/controllers/maps_spec.rb b/spec/controllers/maps_spec.rb index fc06c15cd..f3cd2d9bc 100644 --- a/spec/controllers/maps_spec.rb +++ b/spec/controllers/maps_spec.rb @@ -1,30 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe MapsController, :type => :controller do - describe 'authorization' do +describe MapsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'all_supporters' do - include_context :open_to_super_admin, :get, :all_supporters, with_status: 200 + describe "rejects unauthorized users" do + describe "all_supporters" do + include_context :open_to_super_admin, :get, :all_supporters, with_status: 200 end - describe 'all_npo_supporters' do - include_context :open_to_np_associate, :get, :all_npo_supporters, nonprofit_id: :__our_np, with_status: 200 + describe "all_npo_supporters" do + include_context :open_to_np_associate, :get, :all_npo_supporters, nonprofit_id: :__our_np, with_status: 200 end - describe 'specific_npo_supporters' do - include_context :open_to_np_associate, :get, :specific_npo_supporters, nonprofit_id: :__our_np, with_status: 200 + describe "specific_npo_supporters" do + include_context :open_to_np_associate, :get, :specific_npo_supporters, nonprofit_id: :__our_np, with_status: 200 end end - describe 'open_to_all' do - describe 'all_npos' do - include_context :open_to_all, :get, :all_npos, nonprofit_id: :__our_np, with_status: 200 + describe "open_to_all" do + describe "all_npos" do + include_context :open_to_all, :get, :all_npos, nonprofit_id: :__our_np, with_status: 200 end - - end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/activities_spec.rb b/spec/controllers/nonprofits/activities_spec.rb index ec3dd383c..65dc9332f 100644 --- a/spec/controllers/nonprofits/activities_spec.rb +++ b/spec/controllers/nonprofits/activities_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::ActivitiesController, :type => :controller do - describe 'authorization' do +describe Nonprofits::ActivitiesController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'get' do + describe "rejects unauthorized users" do + describe "get" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, supporter_id: 1111 end end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/bank_accounts_spec.rb b/spec/controllers/nonprofits/bank_accounts_spec.rb index d65d94037..8969a904a 100644 --- a/spec/controllers/nonprofits/bank_accounts_spec.rb +++ b/spec/controllers/nonprofits/bank_accounts_spec.rb @@ -1,32 +1,32 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::BankAccountsController, :type => :controller do +describe Nonprofits::BankAccountsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'create' do + describe "rejects unauthenticated users" do + describe "create" do include_context :open_to_np_admin, :post, :create, nonprofit_id: :__our_np end - describe 'confirmation' do + describe "confirmation" do include_context :open_to_np_admin, :get, :confirmation, nonprofit_id: :__our_np, without_json_view: true end - describe 'confirm' do + describe "confirm" do include_context :open_to_np_admin, :post, :confirm, nonprofit_id: :__our_np end - describe 'cancellation' do + describe "cancellation" do include_context :open_to_np_admin, :get, :cancellation, nonprofit_id: :__our_np, without_json_view: true end - describe 'cancel' do + describe "cancel" do include_context :open_to_np_admin, :post, :cancel, nonprofit_id: :__our_np end - describe 'resend_confirmation' do + describe "resend_confirmation" do include_context :open_to_np_admin, :post, :resend_confirmation, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/button_spec.rb b/spec/controllers/nonprofits/button_spec.rb index ec0cfbc2d..e8cbe63fe 100644 --- a/spec/controllers/nonprofits/button_spec.rb +++ b/spec/controllers/nonprofits/button_spec.rb @@ -1,26 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::ButtonController, :type => :controller do +describe Nonprofits::ButtonController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'send_code' do + describe "rejects unauthenticated users" do + describe "send_code" do include_context :open_to_registered, :get, :send_code, nonprofit_id: :__our_np end - describe 'basic' do + describe "basic" do include_context :open_to_registered, :get, :basic, nonprofit_id: :__our_np, without_json_view: true end - describe 'guided' do + describe "guided" do include_context :open_to_registered, :get, :guided, nonprofit_id: :__our_np, without_json_view: true end - describe 'advanced' do + describe "advanced" do include_context :open_to_registered, :get, :advanced, nonprofit_id: :__our_np, without_json_view: true end - - end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/charges_spec.rb b/spec/controllers/nonprofits/charges_spec.rb index 0bc2f4fd1..5b31de3e7 100644 --- a/spec/controllers/nonprofits/charges_spec.rb +++ b/spec/controllers/nonprofits/charges_spec.rb @@ -1,12 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::ChargesController, :type => :controller do +describe Nonprofits::ChargesController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'get' do + describe "rejects unauthenticated users" do + describe "get" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/custom_field_masters_spec.rb b/spec/controllers/nonprofits/custom_field_masters_spec.rb index 5c483cc6f..aa1cd062c 100644 --- a/spec/controllers/nonprofits/custom_field_masters_spec.rb +++ b/spec/controllers/nonprofits/custom_field_masters_spec.rb @@ -1,20 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::CustomFieldMastersController, :type => :controller do +describe Nonprofits::CustomFieldMastersController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'get custom field masters' do - include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, with_status: 200 + describe "rejects unauthenticated users" do + describe "get custom field masters" do + include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, with_status: 200 end - describe 'create' do + describe "create" do include_context :open_to_np_associate, :post, :create, nonprofit_id: :__our_np end - describe 'destroy' do - include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: '1' + describe "destroy" do + include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: "1" end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/custom_fields_joins_spec.rb b/spec/controllers/nonprofits/custom_fields_joins_spec.rb index 6da79d8a9..6c7cb85bb 100644 --- a/spec/controllers/nonprofits/custom_fields_joins_spec.rb +++ b/spec/controllers/nonprofits/custom_fields_joins_spec.rb @@ -1,20 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::CustomFieldJoinsController, :type => :controller do +describe Nonprofits::CustomFieldJoinsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'index' do + describe "rejects unauthenticated users" do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, supporter_id: 1, with_status: 200 end - describe 'modify' do - include_context :open_to_np_associate, :post, :modify, nonprofit_id: :__our_np, id: '1' + describe "modify" do + include_context :open_to_np_associate, :post, :modify, nonprofit_id: :__our_np, id: "1" end - describe 'destroy' do - include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: '1', supporter_id: 1 + describe "destroy" do + include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: "1", supporter_id: 1 end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/donations_spec.rb b/spec/controllers/nonprofits/donations_spec.rb index b76bcb747..83d825988 100644 --- a/spec/controllers/nonprofits/donations_spec.rb +++ b/spec/controllers/nonprofits/donations_spec.rb @@ -1,45 +1,44 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' -require 'controllers/support/new_controller_user_context' -require 'support/contexts/shared_donation_charge_context' +require "rails_helper" +require "controllers/support/shared_user_context" +require "controllers/support/new_controller_user_context" +require "support/contexts/shared_donation_charge_context" -describe Nonprofits::DonationsController, :type => :controller do - - describe 'rejects unauthenticated users' do - describe 'index' do +describe Nonprofits::DonationsController, type: :controller do + describe "rejects unauthenticated users" do + describe "index" do include_context :shared_user_context - include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, id: '1' + include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, id: "1" end - describe 'update' do + describe "update" do include_context :shared_user_context - include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: '1' + include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: "1" end end - describe 'accept all users' do - describe 'create' do + describe "accept all users" do + describe "create" do include_context :open_to_all, :get, :create, nonprofit_id: :__our_np end - describe 'follow up' do - include_context :open_to_all, :put, :followup, nonprofit_id: :__our_np, id: '1' + describe "follow up" do + include_context :open_to_all, :put, :followup, nonprofit_id: :__our_np, id: "1" end end end -describe 'Nonprofits::DonationsController::create_offsite', :type => :request do - describe 'create_offsite' do +describe "Nonprofits::DonationsController::create_offsite", type: :request do + describe "create_offsite" do include_context :shared_donation_charge_context include_context :new_controller_user_context - it 'reject non-campaign editors (and np authorized folks)' do + it "reject non-campaign editors (and np authorized folks)" do run_authorization_tests({method: :post, action: "/nonprofits/#{nonprofit.id}/donations/create_offsite", successful_users: roles__open_to_campaign_editor}) do |_| - { params: {nonprofit_id: nonprofit.id, - donation: {campaign_id: campaign.id}} } + {params: {nonprofit_id: nonprofit.id, + donation: {campaign_id: campaign.id}}} end end - #include_context :open_to_np_associate, :post, :create_offsite, nonprofit_id: :__our_np + # include_context :open_to_np_associate, :post, :create_offsite, nonprofit_id: :__our_np end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/email_lists_spec.rb b/spec/controllers/nonprofits/email_lists_spec.rb index 737f3e621..f50faee72 100644 --- a/spec/controllers/nonprofits/email_lists_spec.rb +++ b/spec/controllers/nonprofits/email_lists_spec.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::EmailListsController, :type => :controller do +describe Nonprofits::EmailListsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'index' do + describe "rejects unauthenticated users" do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np end - describe 'create' do + describe "create" do include_context :open_to_np_associate, :post, :create, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/imports_spec.rb b/spec/controllers/nonprofits/imports_spec.rb index 93f2f8337..35ac0874e 100644 --- a/spec/controllers/nonprofits/imports_spec.rb +++ b/spec/controllers/nonprofits/imports_spec.rb @@ -1,12 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::ImportsController, :type => :controller do +describe Nonprofits::ImportsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'create' do + describe "rejects unauthenticated users" do + describe "create" do include_context :open_to_np_associate, :post, :create, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/miscellaneous_np_infos_spec.rb b/spec/controllers/nonprofits/miscellaneous_np_infos_spec.rb index 2c6f7720c..2a183bb33 100644 --- a/spec/controllers/nonprofits/miscellaneous_np_infos_spec.rb +++ b/spec/controllers/nonprofits/miscellaneous_np_infos_spec.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::MiscellaneousNpInfosController, :type => :controller do +describe Nonprofits::MiscellaneousNpInfosController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'show' do + describe "rejects unauthenticated users" do + describe "show" do include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np end - describe 'update' do + describe "update" do include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/nonprofit_keys_spec.rb b/spec/controllers/nonprofits/nonprofit_keys_spec.rb index c2b65b351..36270865f 100644 --- a/spec/controllers/nonprofits/nonprofit_keys_spec.rb +++ b/spec/controllers/nonprofits/nonprofit_keys_spec.rb @@ -1,18 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::NonprofitKeysController, :type => :controller do +describe Nonprofits::NonprofitKeysController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'index' do + describe "rejects unauthenticated users" do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np end - describe 'mailchimp_login' do + describe "mailchimp_login" do include_context :open_to_np_associate, :get, :mailchimp_login, nonprofit_id: :__our_np - it 'properly redirects to a mailchimp domain' do + it "properly redirects to a mailchimp domain" do sign_in user_as_np_admin get :mailchimp_login, params: {nonprofit_id: nonprofit.id} @@ -21,8 +21,8 @@ end end - describe 'mailchimp_landing' do + describe "mailchimp_landing" do include_context :open_to_np_associate, :get, :mailchimp_landing, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/payments_spec.rb b/spec/controllers/nonprofits/payments_spec.rb index 8b2a5a0e8..bc2e4d7e8 100644 --- a/spec/controllers/nonprofits/payments_spec.rb +++ b/spec/controllers/nonprofits/payments_spec.rb @@ -1,28 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::PaymentsController, :type => :controller do +describe Nonprofits::PaymentsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'get payments' do + describe "rejects unauthenticated users" do + describe "get payments" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, without_json_view: true end - describe 'export payments' do + describe "export payments" do include_context :open_to_np_associate, :get, :export, nonprofit_id: :__our_np end - describe 'show payments' do - include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: '1', with_status: 200 + describe "show payments" do + include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: "1", with_status: 200 end - describe 'update' do - include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: '1' + describe "update" do + include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: "1" end - describe 'destroy payment' do - include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: '1' + describe "destroy payment" do + include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: "1" end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/payouts_spec.rb b/spec/controllers/nonprofits/payouts_spec.rb index a00246644..5a2c4686d 100644 --- a/spec/controllers/nonprofits/payouts_spec.rb +++ b/spec/controllers/nonprofits/payouts_spec.rb @@ -1,20 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::PayoutsController, :type => :controller do +describe Nonprofits::PayoutsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'create' do + describe "rejects unauthenticated users" do + describe "create" do include_context :open_to_np_admin, :post, :create, nonprofit_id: :__our_np end - describe 'index' do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, without_json_view: true end - describe 'show' do - include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: '1' + describe "show" do + include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: "1" end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/recurring_donations_spec.rb b/spec/controllers/nonprofits/recurring_donations_spec.rb index ad1193f54..e90364195 100644 --- a/spec/controllers/nonprofits/recurring_donations_spec.rb +++ b/spec/controllers/nonprofits/recurring_donations_spec.rb @@ -1,34 +1,34 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::RecurringDonationsController, :type => :controller do +describe Nonprofits::RecurringDonationsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'index' do + describe "rejects unauthenticated users" do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, without_json_view: true end - describe 'export' do + describe "export" do include_context :open_to_np_associate, :post, :export, nonprofit_id: :__our_np end - describe 'show' do - include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: '1', with_status: 200 + describe "show" do + include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: "1", with_status: 200 end - describe 'destroy' do - include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: '1' + describe "destroy" do + include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: "1" end - describe 'update' do - include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: '1' + describe "update" do + include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: "1" end end - describe 'open for all' do - describe 'create' do + describe "open for all" do + describe "create" do include_context :open_to_all, :post, :create, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/reports_spec.rb b/spec/controllers/nonprofits/reports_spec.rb index 203d51e2d..ff059c3cd 100644 --- a/spec/controllers/nonprofits/reports_spec.rb +++ b/spec/controllers/nonprofits/reports_spec.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::ReportsController, :type => :controller do +describe Nonprofits::ReportsController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'end_of_year' do + describe "rejects unauthenticated users" do + describe "end_of_year" do include_context :open_to_np_associate, :get, :end_of_year, nonprofit_id: :__our_np end - describe 'end_of_year_custom' do + describe "end_of_year_custom" do include_context :open_to_np_associate, :get, :end_of_year_custom, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/stripe_accounts_controller_spec.rb b/spec/controllers/nonprofits/stripe_accounts_controller_spec.rb index e6aba8b05..87830dd7c 100644 --- a/spec/controllers/nonprofits/stripe_accounts_controller_spec.rb +++ b/spec/controllers/nonprofits/stripe_accounts_controller_spec.rb @@ -1,5 +1,4 @@ -require 'rails_helper' +require "rails_helper" -RSpec.describe Nonprofits::StripeAccountsController, :type => :controller do - +RSpec.describe Nonprofits::StripeAccountsController, type: :controller do end diff --git a/spec/controllers/nonprofits/supporters_spec.rb b/spec/controllers/nonprofits/supporters_spec.rb index a8597da3b..3a5cd5436 100644 --- a/spec/controllers/nonprofits/supporters_spec.rb +++ b/spec/controllers/nonprofits/supporters_spec.rb @@ -1,50 +1,50 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::SupportersController, :type => :controller do +describe Nonprofits::SupportersController, type: :controller do include_context :shared_user_context - describe 'rejects unauthenticated users' do - describe 'index' do + describe "rejects unauthenticated users" do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, without_json_view: true end - describe 'index_metrics' do + describe "index_metrics" do include_context :open_to_np_associate, :get, :index_metrics, nonprofit_id: :__our_np end - describe 'show' do - include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: '1' + describe "show" do + include_context :open_to_np_associate, :get, :show, nonprofit_id: :__our_np, id: "1" end - describe 'email_address' do - include_context :open_to_np_associate, :get, :email_address, nonprofit_id: :__our_np, id: '1' + describe "email_address" do + include_context :open_to_np_associate, :get, :email_address, nonprofit_id: :__our_np, id: "1" end - describe 'full_contact' do - include_context :open_to_np_associate, :get, :full_contact, nonprofit_id: :__our_np, id: '1' + describe "full_contact" do + include_context :open_to_np_associate, :get, :full_contact, nonprofit_id: :__our_np, id: "1" end - describe 'info_card' do - include_context :open_to_np_associate, :get, :info_card, nonprofit_id: :__our_np, id: '1' + describe "info_card" do + include_context :open_to_np_associate, :get, :info_card, nonprofit_id: :__our_np, id: "1" end - describe 'update' do - include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: '1' + describe "update" do + include_context :open_to_np_associate, :put, :update, nonprofit_id: :__our_np, id: "1" end - describe 'bulk_delete' do + describe "bulk_delete" do include_context :open_to_np_associate, :delete, :bulk_delete, nonprofit_id: :__our_np end - describe 'merge' do + describe "merge" do include_context :open_to_np_associate, :delete, :bulk_delete, nonprofit_id: :__our_np end end - describe 'accept all users' do - describe 'create' do + describe "accept all users" do + describe "create" do include_context :open_to_all, :post, :create, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/tag_joins_spec.rb b/spec/controllers/nonprofits/tag_joins_spec.rb index aff87faeb..b79cfb4f3 100644 --- a/spec/controllers/nonprofits/tag_joins_spec.rb +++ b/spec/controllers/nonprofits/tag_joins_spec.rb @@ -1,42 +1,42 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::TagJoinsController, :type => :controller do - describe 'authorization' do +describe Nonprofits::TagJoinsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'index' do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np, supporter_id: 1 end - describe 'modify' do - include_context :open_to_np_associate, :post, :modify, nonprofit_id: :__our_np, id: '1' + describe "modify" do + include_context :open_to_np_associate, :post, :modify, nonprofit_id: :__our_np, id: "1" - context 'strong params' do - let(:supporter) { create(:supporter_base)} + context "strong params" do + let(:supporter) { create(:supporter_base) } let(:nonprofit) { supporter.nonprofit } let(:tag_master) { create(:tag_master_base, nonprofit: nonprofit) } before(:each) do sign_in create(:user_as_nonprofit_admin, nonprofit: nonprofit) end - + let(:params) do { nonprofit_id: nonprofit.id, - supporter_ids: [supporter.id], + supporter_ids: [supporter.id], tags: [ { tag_master_id: tag_master.id, selected: true, supporter_id: :invalid, # proves that the permit strips this out - something_else: :invalid, # proves that the permit strips this out + something_else: :invalid # proves that the permit strips this out } ] - } + } end - it 'succeeds' do + it "succeeds" do post :modify, params: params expect(supporter.tag_joins.count).to eq 1 end @@ -45,7 +45,7 @@ # We can turn this back on in newer versions and see if it works # 1) Nonprofits::TagJoinsController authorization modify permitting is expected to (for POST #modify) restrict parameters on :tags to :tag_master_id # Failure/Error: modify_params.require(:tags) - + # NameError: # undefined method `permit' for class `#>' # Did you mean? print @@ -57,11 +57,10 @@ # it { is_expected.to permit(:tag_master_id).for(:modify, params: params, verb: :post).on(:tags) } end - end - describe 'destroy' do - include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: '1', supporter_id: 2 + describe "destroy" do + include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: "1", supporter_id: 2 end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/tag_masters_spec.rb b/spec/controllers/nonprofits/tag_masters_spec.rb index c39f931ce..ceff51e3f 100644 --- a/spec/controllers/nonprofits/tag_masters_spec.rb +++ b/spec/controllers/nonprofits/tag_masters_spec.rb @@ -1,22 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::TagMastersController, :type => :controller do - describe 'authorization' do +describe Nonprofits::TagMastersController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'index' do + describe "rejects unauthorized users" do + describe "index" do include_context :open_to_np_associate, :get, :index, nonprofit_id: :__our_np end - describe 'create' do + describe "create" do include_context :open_to_np_associate, :post, :create, nonprofit_id: :__our_np end - describe 'destroy' do - include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: '1' + describe "destroy" do + include_context :open_to_np_associate, :delete, :destroy, nonprofit_id: :__our_np, id: "1" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits/trackings_spec.rb b/spec/controllers/nonprofits/trackings_spec.rb index fd27c4f97..0bfa5fb68 100644 --- a/spec/controllers/nonprofits/trackings_spec.rb +++ b/spec/controllers/nonprofits/trackings_spec.rb @@ -1,12 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Nonprofits::TrackingsController, :type => :controller do +describe Nonprofits::TrackingsController, type: :controller do include_context :shared_user_context - describe 'open to all' do - describe 'create' do - include_context :open_to_all, :post, :create, nonprofit_id: :__our_np + describe "open to all" do + describe "create" do + include_context :open_to_all, :post, :create, nonprofit_id: :__our_np end end -end \ No newline at end of file +end diff --git a/spec/controllers/nonprofits_spec.rb b/spec/controllers/nonprofits_spec.rb index 37f0a3606..2516fd05d 100644 --- a/spec/controllers/nonprofits_spec.rb +++ b/spec/controllers/nonprofits_spec.rb @@ -1,72 +1,72 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe NonprofitsController, :type => :controller do - describe 'authorization' do +describe NonprofitsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'update' do + describe "rejects unauthorized users" do + describe "update" do include_context :open_to_np_associate, :put, :update, id: :__our_np end - describe 'dashboard' do + describe "dashboard" do include_context :open_to_np_associate, :get, :dashboard, id: :__our_np, without_json_view: true end - describe 'dashboard_metrics' do + describe "dashboard_metrics" do include_context :open_to_np_associate, :get, :dashboard_metrics, id: :__our_np end - describe 'recurring_donation_stats' do + describe "recurring_donation_stats" do include_context :open_to_np_associate, :get, :recurring_donation_stats, id: :__our_np end - describe 'profile_todos' do + describe "profile_todos" do include_context :open_to_np_associate, :get, :profile_todos, id: :__our_np end - describe 'dashboard_todos' do + describe "dashboard_todos" do include_context :open_to_np_associate, :get, :dashboard_todos, id: :__our_np end - describe 'payment_history' do + describe "payment_history" do include_context :open_to_np_associate, :get, :payment_history, id: :__our_np end - describe 'destroy' do + describe "destroy" do include_context :open_to_super_admin, :delete, :destroy, id: :__our_np end end - describe 'open to all' do - describe 'show' do + describe "open to all" do + describe "show" do include_context :open_to_all, :get, :show, id: :__our_np, without_json_view: true end - describe 'create' do + describe "create" do include_context :open_to_all, :post, :create, nonprofit_id: :__our_np end - describe 'btn' do + describe "btn" do include_context :open_to_all, :get, :btn, id: :__our_np, without_json_view: true end - describe 'supporter_form' do + describe "supporter_form" do include_context :open_to_all, :get, :supporter_form, id: :__our_np, without_json_view: true end - describe 'custom_supporter' do + describe "custom_supporter" do include_context :open_to_all, :post, :custom_supporter, id: :__our_np end - describe 'donate' do + describe "donate" do include_context :open_to_all, :get, :donate, id: :__our_np, without_json_view: true end - describe 'search' do + describe "search" do include_context :open_to_all, :get, :search end end end -end \ No newline at end of file +end diff --git a/spec/controllers/onboard_controller_spec.rb b/spec/controllers/onboard_controller_spec.rb index 0471da112..934611744 100644 --- a/spec/controllers/onboard_controller_spec.rb +++ b/spec/controllers/onboard_controller_spec.rb @@ -1,5 +1,4 @@ -require 'rails_helper' - -RSpec.describe OnboardController, :type => :controller do +require "rails_helper" +RSpec.describe OnboardController, type: :controller do end diff --git a/spec/controllers/profiles_spec.rb b/spec/controllers/profiles_spec.rb index 0199f18c0..f87be88a7 100644 --- a/spec/controllers/profiles_spec.rb +++ b/spec/controllers/profiles_spec.rb @@ -1,28 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe ProfilesController, :type => :controller do - describe 'authorization' do +describe ProfilesController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'update' do + describe "rejects unauthorized users" do + describe "update" do include_context :open_to_profile_owner, :put, :update, id: :__our_profile end - describe 'fundraisers' do + describe "fundraisers" do include_context :open_to_profile_owner, :get, :fundraisers, id: :__our_profile, without_json_view: true end - describe 'donations_history' do + describe "donations_history" do include_context :open_to_profile_owner, :get, :donations_history, id: :__our_profile, without_json_view: true end end - describe 'open to all' do - describe 'show' do + describe "open to all" do + describe "show" do include_context :open_to_all, :get, :show, id: :__our_np, without_json_view: true end end end -end \ No newline at end of file +end diff --git a/spec/controllers/recurring_donations_spec.rb b/spec/controllers/recurring_donations_spec.rb index 72be22452..910743209 100644 --- a/spec/controllers/recurring_donations_spec.rb +++ b/spec/controllers/recurring_donations_spec.rb @@ -1,26 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe RecurringDonationsController, :type => :controller do - describe 'authorization' do +describe RecurringDonationsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'open to all (note: edit token is checked inside methods)' do - describe 'edit' do - include_context :open_to_all, :get, :edit, nonprofit_id: :__our_np, id: '1', without_json_view: true + describe "open to all (note: edit token is checked inside methods)" do + describe "edit" do + include_context :open_to_all, :get, :edit, nonprofit_id: :__our_np, id: "1", without_json_view: true end - describe 'destroy' do - include_context :open_to_all, :delete, :destroy, nonprofit_id: :__our_np, id: '1' + describe "destroy" do + include_context :open_to_all, :delete, :destroy, nonprofit_id: :__our_np, id: "1" end - describe 'update' do - include_context :open_to_all, :put, :update, nonprofit_id: :__our_np, id: '1' + describe "update" do + include_context :open_to_all, :put, :update, nonprofit_id: :__our_np, id: "1" end - describe 'update_amount' do - include_context :open_to_all, :put, :update_amount, nonprofit_id: :__our_np, id: '1' + describe "update_amount" do + include_context :open_to_all, :put, :update_amount, nonprofit_id: :__our_np, id: "1" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/roles_spec.rb b/spec/controllers/roles_spec.rb index 74d89c741..6b3348c95 100644 --- a/spec/controllers/roles_spec.rb +++ b/spec/controllers/roles_spec.rb @@ -1,18 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe RolesController, :type => :controller do - describe 'authorization' do +describe RolesController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do + describe "rejects unauthorized users" do + describe "create" do include_context :open_to_np_admin, :post, :create, nonprofit_id: :__our_np end - describe 'destroy' do - include_context :open_to_np_admin, :delete, :destroy, nonprofit_id: :__our_np, id: '1' + describe "destroy" do + include_context :open_to_np_admin, :delete, :destroy, nonprofit_id: :__our_np, id: "1" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/settings_spec.rb b/spec/controllers/settings_spec.rb index 03dca43ea..ac45946ea 100644 --- a/spec/controllers/settings_spec.rb +++ b/spec/controllers/settings_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe SettingsController, :type => :controller do - describe 'authorization' do +describe SettingsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'index' do + describe "rejects unauthorized users" do + describe "index" do include_context :open_to_registered, :get, :index, nonprofit_id: :__our_np, without_json_view: true end end end -end \ No newline at end of file +end diff --git a/spec/controllers/static_controller_spec.rb b/spec/controllers/static_controller_spec.rb index dc1a1a88d..38845584e 100644 --- a/spec/controllers/static_controller_spec.rb +++ b/spec/controllers/static_controller_spec.rb @@ -1,45 +1,45 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe StaticController, :type => :controller do +RSpec.describe StaticController, type: :controller do describe ".ccs" do around(:each) do |example| example.run Settings.reload! end - describe 'local_tar_gz' do - before (:each) do + describe "local_tar_gz" do + before(:each) do Settings.merge!( - { - ccs: { - ccs_method: 'local_tar_gz', - } - }) + { + ccs: { + ccs_method: "local_tar_gz" + } + } + ) end - - it 'fails on git archive' do + it "fails on git archive" do expect(Kernel).to receive(:system).and_return(false) - get('ccs') + get("ccs") expect(response.status).to eq 500 end - end - it 'setup github' do + it "setup github" do Settings.merge!( - { - ccs: { - ccs_method: 'github', - options: { - account: 'account', - repo: 'repo' - } - } - }) - expect(File).to receive(:read).with("#{Rails.root}/CCS_HASH").and_return("hash\n") - get('ccs') + { + ccs: { + ccs_method: "github", + options: { + account: "account", + repo: "repo" + } + } + } + ) + expect(File).to receive(:read).with("#{Rails.root.join("CCS_HASH")}").and_return("hash\n") + get("ccs") expect(response).to redirect_to "https://github.com/account/repo/tree/hash" end end diff --git a/spec/controllers/stripe/stripe_controller_spec.rb b/spec/controllers/stripe/stripe_controller_spec.rb index 5bc606066..1b18c4ac6 100644 --- a/spec/controllers/stripe/stripe_controller_spec.rb +++ b/spec/controllers/stripe/stripe_controller_spec.rb @@ -1,37 +1,36 @@ -require 'rails_helper' - -RSpec.describe Webhooks::StripeController, :type => :controller do +require "rails_helper" +RSpec.describe Webhooks::StripeController, type: :controller do describe "POST #receive" do - describe 'verification of input' do - it 'returns on bad json' do + describe "verification of input" do + it "returns on bad json" do expect(JSON).to receive(:parse).and_raise(JSON::ParserError) post :receive expect(response.body).to include("Invalid payload") expect(response.status).to eq 400 end - it 'returns on bad signature' do + it "returns on bad signature" do post :receive, body: {}.to_json - expect(response.body).to include('Invalid signature') + expect(response.body).to include("Invalid signature") expect(response.status).to eq 400 end - it 'returns on other error' do + it "returns on other error" do expect(JSON).to receive(:parse).and_raise(ArgumentError) - request.headers['HTTP_STRIPE_SIGNATURE']= "" + request.headers["HTTP_STRIPE_SIGNATURE"] = "" post :receive, body: {}.to_json expect(response.body).to include("Unspecified error") expect(response.status).to eq 400 end end - it 'succeeds' do + it "succeeds" do event = Object.new expect(Stripe::Webhook).to receive(:construct_event).and_return(event) expect(StripeEvent).to receive(:handle).with(event) post :receive, body: {}.to_json - expect(response.body).to eq ({}.to_json) + expect(response.body).to eq({}.to_json) expect(response.status).to eq 200 end end @@ -46,35 +45,35 @@ # end # end - describe 'verification of input' do - it 'returns on bad json' do + describe "verification of input" do + it "returns on bad json" do expect(JSON).to receive(:parse).and_raise(JSON::ParserError) post :receive_connect expect(response.body).to include("Invalid payload") expect(response.status).to eq 400 end - it 'returns on bad signature' do - post :receive_connect, body:{}.to_json - expect(response.body).to include('Invalid signature') + it "returns on bad signature" do + post :receive_connect, body: {}.to_json + expect(response.body).to include("Invalid signature") expect(response.status).to eq 400 end - it 'returns on other error' do + it "returns on other error" do expect(JSON).to receive(:parse).and_raise(ArgumentError) - request.headers['HTTP_STRIPE_SIGNATURE']= "" + request.headers["HTTP_STRIPE_SIGNATURE"] = "" post :receive_connect, body: {}.to_json expect(response.body).to include("Unspecified error") expect(response.status).to eq 400 end end - it 'succeeds' do + it "succeeds" do event = Object.new expect(Stripe::Webhook).to receive(:construct_event).and_return(event) expect(StripeEvent).to receive(:handle).with(event) - post :receive_connect, body:{}.to_json - expect(response.body).to eq ({}.to_json) + post :receive_connect, body: {}.to_json + expect(response.body).to eq({}.to_json) expect(response.status).to eq 200 end end diff --git a/spec/controllers/super_admins_spec.rb b/spec/controllers/super_admins_spec.rb index 5a402215f..419470bbc 100644 --- a/spec/controllers/super_admins_spec.rb +++ b/spec/controllers/super_admins_spec.rb @@ -1,28 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe SuperAdminsController, :type => :controller do - describe 'authorization' do +describe SuperAdminsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'search_nonprofits' do - include_context :open_to_super_admin, :get, :search_nonprofits + describe "rejects unauthorized users" do + describe "search_nonprofits" do + include_context :open_to_super_admin, :get, :search_nonprofits end - describe 'search_profiles' do - include_context :open_to_super_admin, :get, :search_profiles + describe "search_profiles" do + include_context :open_to_super_admin, :get, :search_profiles end - describe 'search_fullcontact' do - include_context :open_to_super_admin, :get, :search_fullcontact + describe "search_fullcontact" do + include_context :open_to_super_admin, :get, :search_fullcontact end - describe 'index' do - include_context :open_to_super_admin, :get, :index, without_json_view: true + describe "index" do + include_context :open_to_super_admin, :get, :index, without_json_view: true end - - end end -end \ No newline at end of file +end diff --git a/spec/controllers/support/new_controller_user_context.rb b/spec/controllers/support/new_controller_user_context.rb index f83efbc00..a03842434 100644 --- a/spec/controllers/support/new_controller_user_context.rb +++ b/spec/controllers/support/new_controller_user_context.rb @@ -1,33 +1,33 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'support/contexts/general_shared_user_context' +require "support/contexts/general_shared_user_context" RSpec.shared_context :new_controller_user_context do include_context :general_shared_user_context def sign_in(user_to_signin) - post '/users/sign_in', params: {'user[email]' => user_to_signin.email, 'user[password]' => user_to_signin.password, format: "json"} + post "/users/sign_in", params: {"user[email]" => user_to_signin.email, "user[password]" => user_to_signin.password, :format => "json"} end def sign_out - send(:get, '/users/sign_out') + send(:get, "/users/sign_out") end - def send(method, action, opts={}) + def send(method, action, opts = {}) case method when :get - return get action, **opts.merge(xhr: true) + get action, **opts.merge(xhr: true) when :post - return post action, **opts.merge(xhr: true) + post action, **opts.merge(xhr: true) when :delete - return delete action, **opts.merge(xhr: true) + delete action, **opts.merge(xhr: true) when :put - return put action, **opts.merge(xhr: true) + put action, **opts.merge(xhr: true) end end def accept(user_to_signin:, method:, action:, args:) new_user = user_to_signin - if (user_to_signin != nil && user_to_signin.is_a?(OpenStruct)) + if !user_to_signin.nil? && user_to_signin.is_a?(OpenStruct) new_user = user_to_signin.value end sign_in new_user if new_user @@ -35,19 +35,18 @@ def accept(user_to_signin:, method:, action:, args:) # expect_any_instance_of(described_class).to receive(action).and_return(ActionController::TestResponse.new(200)) # expect_any_instance_of(described_class).to receive(:render).and_return(nil) send(method, action, args) - expect(response.status).to_not eq(302), "expected success for user: #{(user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ":" : "")} #{new_user&.attributes}" + expect(response.status).to_not eq(302), "expected success for user: #{user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ":" : ""} #{new_user&.attributes}" sign_out end def reject(user_to_signin:, method:, action:, args:) - new_user = user_to_signin - if (user_to_signin != nil && user_to_signin.is_a?(OpenStruct)) + if !user_to_signin.nil? && user_to_signin.is_a?(OpenStruct) new_user = user_to_signin.value end sign_in new_user if new_user send(method, action, args) - expect(response.status).to eq(302), "expected failure for user: #{(user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ":" : "")} #{new_user&.attributes}" + expect(response.status).to eq(302), "expected failure for user: #{user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ":" : ""} #{new_user&.attributes}" sign_out end -end \ No newline at end of file +end diff --git a/spec/controllers/support/shared_user_context.rb b/spec/controllers/support/shared_user_context.rb index d63c5dd2e..740615d14 100644 --- a/spec/controllers/support/shared_user_context.rb +++ b/spec/controllers/support/shared_user_context.rb @@ -1,27 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - RSpec.shared_context :shared_user_context do - - - let(:nonprofit) {create(:nonprofit_base, published:true)} - let(:other_nonprofit) { create(:nonprofit_base)} - + let(:nonprofit) { create(:nonprofit_base, published: true) } + let(:other_nonprofit) { create(:nonprofit_base) } let(:user_as_np_admin) { __create_admin(nonprofit) } - let(:user_as_other_np_admin) { __create_admin(other_nonprofit) } - let(:user_as_np_associate){ + let(:user_as_np_associate) { __create_associate(nonprofit) } - let(:user_as_other_np_associate){ + let(:user_as_other_np_associate) { __create_associate(other_nonprofit) } @@ -29,12 +24,12 @@ force_create(:user) } - let(:campaign) {force_create(:campaign, nonprofit: nonprofit)} + let(:campaign) { force_create(:campaign, nonprofit: nonprofit) } let(:campaign_editor) { __create(:campaign_editor, campaign) } - let(:confirmed_user){ + let(:confirmed_user) { force_create(:user, confirmed_at: Time.current) } @@ -43,11 +38,11 @@ } let(:event_editor) { - __create(:event_editor,event) + __create(:event_editor, event) } let(:super_admin) { - __create(:super_admin, other_nonprofit) + __create(:super_admin, other_nonprofit) } let(:user_with_profile) { @@ -56,42 +51,40 @@ u } - - def __create(name, host) u = force_create(:user) - force_create(:role, user: u, name: name, host:host) + force_create(:role, user: u, name: name, host: host) u end def __create_admin(host) u = force_create(:user) - force_create(:role, user: u, name: :nonprofit_admin, host:host) + force_create(:role, user: u, name: :nonprofit_admin, host: host) u end def __create_associate(host) u = force_create(:user) - force_create(:role, user: u, name: :nonprofit_associate, host:host) + force_create(:role, user: u, name: :nonprofit_associate, host: host) u end - def send(method, action, args={}) + def send(method, action, args = {}) case method - when :get - return get(action, **args) - when :post - return post(action, **args) - when :delete - return delete(action, **args) - when :put - return put(action, **args) + when :get + get(action, **args) + when :post + post(action, **args) + when :delete + delete(action, **args) + when :put + put(action, **args) end end def accept(user_to_signin, method, action, *args) test_variables = collect_test_variables(args) - request.accept = 'application/json' unless test_variables[:without_json_view] + request.accept = "application/json" unless test_variables[:without_json_view] sign_in user_to_signin if user_to_signin expect_any_instance_of(described_class).to receive(action).and_return(ActionDispatch::IntegrationTest.new(200)) @@ -108,517 +101,509 @@ def accept(user_to_signin, method, action, *args) def reject(user_to_signin, method, action, *args) sign_in user_to_signin if user_to_signin - send(method, action, reduce_params(*args)) + send(method, action, reduce_params(*args)) expect(response.status).to eq 302 end alias_method :redirects_to, :reject def reduce_params(*args) - { params: args.reduce({}, :merge) } + {params: args.reduce({}, :merge)} end - + ## the :without_json_view and :with_status arguments aren't passed to context for testing authorization itself, ## they're used for verifying what should be expected. This removes them so you only have the proper context arguments def collect_test_variables(*args) test_vars = {} args.collect do |items| - if items.kind_of?(Array) + if items.is_a?(Array) items.each do |k, v| - test_vars.merge!(k.slice(:without_json_view, :with_status)) if k.kind_of?(Hash) + test_vars.merge!(k.slice(:without_json_view, :with_status)) if k.is_a?(Hash) end end end - return test_vars + test_vars end - def fix_args( *args) + def fix_args(*args) replacements = { - __our_np: nonprofit.id, - __our_campaign: campaign.id, - __our_event: event.id, - __our_profile: user_with_profile.profile.id + __our_np: nonprofit.id, + __our_campaign: campaign.id, + __our_event: event.id, + __our_profile: user_with_profile.profile.id } - args.collect{|i| + args.collect { |i| ret = i if replacements[i] ret = replacements[i] elsif i.is_a? Hash - ret = i.collect{|k,v | + ret = i.collect { |k, v| ret_v = v if replacements[v] ret_v = replacements[v] end - [k,ret_v] + [k, ret_v] }.to_h end ret }.to_a end - - end RSpec.shared_context :open_to_all do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'accepts no user' do + it "accepts no user" do accept(nil, method, action, *fixed_args) end - it 'accepts user with no roles' do + it "accepts user with no roles" do accept(unauth_user, method, action, *fixed_args) end - it 'accepts nonprofit admin' do + it "accepts nonprofit admin" do accept(user_as_np_admin, method, action, *fixed_args) end - it 'accepts nonprofit associate' do + it "accepts nonprofit associate" do accept(user_as_np_associate, method, action, *fixed_args) end - it 'accepts other admin' do + it "accepts other admin" do accept(user_as_other_np_admin, method, action, *fixed_args) end - it 'accepts other associate' do + it "accepts other associate" do accept(user_as_other_np_associate, method, action, *fixed_args) end - it 'accepts campaign editor' do + it "accepts campaign editor" do accept(campaign_editor, method, action, *fixed_args) end - it 'accept confirmed user' do + it "accept confirmed user" do accept(confirmed_user, method, action, *fixed_args) end - it 'accept event editor' do + it "accept event editor" do accept(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'accept profile user' do + it "accept profile user" do accept(user_with_profile, method, action, *fixed_args) end - end RSpec.shared_context :open_to_np_associate do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'accepts nonprofit admin' do + it "accepts nonprofit admin" do accept(user_as_np_admin, method, action, *fixed_args) end - it 'accepts nonprofit associate' do + it "accepts nonprofit associate" do accept(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'rejects campaign editor' do + it "rejects campaign editor" do reject(campaign_editor, method, action, *fixed_args) end - it 'rejects confirmed user' do + it "rejects confirmed user" do reject(confirmed_user, method, action, *fixed_args) end - it 'reject event editor' do + it "reject event editor" do reject(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'rejects profile user' do + it "rejects profile user" do reject(user_with_profile, method, action, *fixed_args) end end - RSpec.shared_context :open_to_np_admin do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'accepts nonprofit admin' do + it "accepts nonprofit admin" do accept(user_as_np_admin, method, action, *fixed_args) end - it 'rejects nonprofit associate' do + it "rejects nonprofit associate" do reject(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'rejects campaign editor' do + it "rejects campaign editor" do reject(campaign_editor, method, action, *fixed_args) end - it 'rejects confirmed user' do + it "rejects confirmed user" do reject(confirmed_user, method, action, *fixed_args) end - it 'reject event editor' do + it "reject event editor" do reject(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'rejects profile user' do + it "rejects profile user" do reject(user_with_profile, method, action, *fixed_args) end end RSpec.shared_context :open_to_registered do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'accepts user with no roles' do + it "accepts user with no roles" do accept(unauth_user, method, action, *fixed_args) end - it 'accepts nonprofit admin' do + it "accepts nonprofit admin" do accept(user_as_np_admin, method, action, *fixed_args) end - it 'accepts nonprofit associate' do + it "accepts nonprofit associate" do accept(user_as_np_associate, method, action, *fixed_args) end - it 'accepts other admin' do + it "accepts other admin" do accept(user_as_other_np_admin, method, action, *fixed_args) end - it 'accepts other associate' do + it "accepts other associate" do accept(user_as_other_np_associate, method, action, *fixed_args) end - it 'accepts campaign editor' do + it "accepts campaign editor" do accept(campaign_editor, method, action, *fixed_args) end - it 'accepts confirmed user' do + it "accepts confirmed user" do accept(confirmed_user, method, action, *fixed_args) end - it 'accept event editor' do + it "accept event editor" do accept(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'accept profile user' do + it "accept profile user" do accept(user_with_profile, method, action, *fixed_args) end end - RSpec.shared_context :open_to_campaign_editor do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'accepts nonprofit admin' do + it "accepts nonprofit admin" do accept(user_as_np_admin, method, action, *fixed_args) end - it 'accepts nonprofit associate' do + it "accepts nonprofit associate" do accept(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'accepts campaign editor' do + it "accepts campaign editor" do accept(campaign_editor, method, action, *fixed_args) end - it 'rejects confirmed user' do + it "rejects confirmed user" do reject(confirmed_user, method, action, *fixed_args) end - it 'reject event editor' do + it "reject event editor" do reject(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'rejects profile user' do + it "rejects profile user" do reject(user_with_profile, method, action, *fixed_args) end - end RSpec.shared_context :open_to_confirmed_users do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'reject nonprofit admin' do + it "reject nonprofit admin" do reject(user_as_np_admin, method, action, *fixed_args) end - it 'reject nonprofit associate' do + it "reject nonprofit associate" do reject(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'reject campaign editor' do + it "reject campaign editor" do reject(campaign_editor, method, action, *fixed_args) end - it 'accepts confirmed user' do + it "accepts confirmed user" do accept(confirmed_user, method, action, *fixed_args) end - it 'reject event editor' do + it "reject event editor" do reject(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'rejects profile user' do + it "rejects profile user" do reject(user_with_profile, method, action, *fixed_args) end - end RSpec.shared_context :open_to_event_editor do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'accept nonprofit admin' do + it "accept nonprofit admin" do accept(user_as_np_admin, method, action, *fixed_args) end - it 'nonprofit associate' do + it "nonprofit associate" do accept(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'reject campaign editor' do + it "reject campaign editor" do reject(campaign_editor, method, action, *fixed_args) end - it 'reject confirmed user' do + it "reject confirmed user" do reject(confirmed_user, method, action, *fixed_args) end - it 'accept event editor' do + it "accept event editor" do accept(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'rejects profile user' do + it "rejects profile user" do reject(user_with_profile, method, action, *fixed_args) end end RSpec.shared_context :open_to_super_admin do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'rejects nonprofit admin' do + it "rejects nonprofit admin" do reject(user_as_np_admin, method, action, *fixed_args) end - it 'rejects nonprofit associate' do + it "rejects nonprofit associate" do reject(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'rejects campaign editor' do + it "rejects campaign editor" do reject(campaign_editor, method, action, *fixed_args) end - it 'rejects confirmed user' do + it "rejects confirmed user" do reject(confirmed_user, method, action, *fixed_args) end - it 'reject event editor' do + it "reject event editor" do reject(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'rejects profile user' do + it "rejects profile user" do reject(user_with_profile, method, action, *fixed_args) end end - RSpec.shared_context :open_to_profile_owner do |method, action, *args| include_context :shared_user_context - let(:fixed_args){ - fix_args( *args) + let(:fixed_args) { + fix_args(*args) } - it 'rejects no user' do + it "rejects no user" do reject(nil, method, action, *fixed_args) end - it 'rejects user with no roles' do + it "rejects user with no roles" do reject(unauth_user, method, action, *fixed_args) end - it 'rejects nonprofit admin' do + it "rejects nonprofit admin" do reject(user_as_np_admin, method, action, *fixed_args) end - it 'rejects nonprofit associate' do + it "rejects nonprofit associate" do reject(user_as_np_associate, method, action, *fixed_args) end - it 'rejects other admin' do + it "rejects other admin" do reject(user_as_other_np_admin, method, action, *fixed_args) end - it 'rejects other associate' do + it "rejects other associate" do reject(user_as_other_np_associate, method, action, *fixed_args) end - it 'rejects campaign editor' do + it "rejects campaign editor" do reject(campaign_editor, method, action, *fixed_args) end - it 'rejects confirmed user' do + it "rejects confirmed user" do reject(confirmed_user, method, action, *fixed_args) end - it 'reject event editor' do + it "reject event editor" do reject(event_editor, method, action, *fixed_args) end - it 'accepts super admin' do + it "accepts super admin" do accept(super_admin, method, action, *fixed_args) end - it 'accepts profile user' do + it "accepts profile user" do accept(user_with_profile, method, action, *fixed_args) end -end \ No newline at end of file +end diff --git a/spec/controllers/ticket_levels_spec.rb b/spec/controllers/ticket_levels_spec.rb index c3eb09ed7..3592eda9d 100644 --- a/spec/controllers/ticket_levels_spec.rb +++ b/spec/controllers/ticket_levels_spec.rb @@ -1,33 +1,33 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe TicketLevelsController, :type => :controller do - describe 'authorization' do +describe TicketLevelsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'create' do - include_context :open_to_event_editor, :post, :create, nonprofit_id: :__our_np, event_id: :__our_event, id: '1' + describe "rejects unauthorized users" do + describe "create" do + include_context :open_to_event_editor, :post, :create, nonprofit_id: :__our_np, event_id: :__our_event, id: "1" end - describe 'update' do - include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, event_id: :__our_event, id: '1' + describe "update" do + include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, event_id: :__our_event, id: "1" end - describe 'update_order' do + describe "update_order" do include_context :open_to_event_editor, :put, :update_order, nonprofit_id: :__our_np, event_id: :__our_event end - describe 'destroy' do - include_context :open_to_event_editor, :delete, :destroy, nonprofit_id: :__our_np, event_id: :__our_event, id: '1' + describe "destroy" do + include_context :open_to_event_editor, :delete, :destroy, nonprofit_id: :__our_np, event_id: :__our_event, id: "1" end end - describe 'open to all' do - describe 'show' do - include_context :open_to_all, :get, :show, nonprofit_id: :__our_np, event_id: :__our_event, id: '2' + describe "open to all" do + describe "show" do + include_context :open_to_all, :get, :show, nonprofit_id: :__our_np, event_id: :__our_event, id: "2" end - describe 'index' do + describe "index" do include_context :open_to_all, :get, :index, nonprofit_id: :__our_np, event_id: :__our_event end end end -end \ No newline at end of file +end diff --git a/spec/controllers/tickets_spec.rb b/spec/controllers/tickets_spec.rb index 0dba7c2dd..d049d6093 100644 --- a/spec/controllers/tickets_spec.rb +++ b/spec/controllers/tickets_spec.rb @@ -1,39 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe TicketsController, :type => :controller do - describe 'authorization' do +describe TicketsController, type: :controller do + describe "authorization" do include_context :shared_user_context - describe 'rejects unauthorized users' do - describe 'update' do - include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, event_id: :__our_event, id:1111 + describe "rejects unauthorized users" do + describe "update" do + include_context :open_to_event_editor, :put, :update, nonprofit_id: :__our_np, event_id: :__our_event, id: 1111 end - describe 'index' do - include_context :open_to_event_editor, :get, :index, nonprofit_id: :__our_np, event_id: :__our_event, without_json_view: true + describe "index" do + include_context :open_to_event_editor, :get, :index, nonprofit_id: :__our_np, event_id: :__our_event, without_json_view: true end - - describe 'destroy' do - include_context :open_to_event_editor, :delete, :destroy, nonprofit_id: :__our_np, event_id: :__our_event, id: 1111 + describe "destroy" do + include_context :open_to_event_editor, :delete, :destroy, nonprofit_id: :__our_np, event_id: :__our_event, id: 1111 end - describe 'delete_card_for_ticket' do - include_context :open_to_np_associate, :post, :delete_card_for_ticket, nonprofit_id: :__our_np, event_id: :__our_event, id: 11_111 + describe "delete_card_for_ticket" do + include_context :open_to_np_associate, :post, :delete_card_for_ticket, nonprofit_id: :__our_np, event_id: :__our_event, id: 11_111 end - - end - describe 'open to all' do - describe 'create' do - include_context :open_to_all, :post, :create, nonprofit_id: :__our_np, event_id: :__our_event + describe "open to all" do + describe "create" do + include_context :open_to_all, :post, :create, nonprofit_id: :__our_np, event_id: :__our_event end - describe 'add_note' do + describe "add_note" do include_context :open_to_all, :put, :add_note, nonprofit_id: :__our_np, event_id: :__our_event, id: 1111 end - end end -end \ No newline at end of file +end diff --git a/spec/controllers/users/registrations_spec.rb b/spec/controllers/users/registrations_spec.rb index 9402c8daa..5d10fb542 100644 --- a/spec/controllers/users/registrations_spec.rb +++ b/spec/controllers/users/registrations_spec.rb @@ -1,32 +1,31 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe Users::RegistrationsController, :type => :controller do +describe Users::RegistrationsController, type: :controller do + it { is_expected.to rescue_from(::Recaptcha::RecaptchaError).with(:handle_recaptcha_failure) } - it {is_expected.to rescue_from(::Recaptcha::RecaptchaError).with(:handle_recaptcha_failure)} - - it {is_expected.to use_before_action(:verify_via_recaptcha!)} + it { is_expected.to use_before_action(:verify_via_recaptcha!) } before do Recaptcha.configuration.enterprise = true end - - after do + + after do Recaptcha.configuration.enterprise = false end - describe '#create' do - context 'recaptcha' do - it 'handles verification failure' do + describe "#create" do + context "recaptcha" do + it "handles verification failure" do expect(controller).to receive(:verify_recaptcha).and_return(false) request.env["devise.mapping"] = Devise.mappings[:user] expect { - post :create, params: {:recaptcha_response_field => "response", 'g-recaptcha-response-data' => 'string', type: :json} - }.to change { RecaptchaRejection.count}.by(1) - + post :create, params: {:recaptcha_response_field => "response", "g-recaptcha-response-data" => "string", :type => :json} + }.to change { RecaptchaRejection.count }.by(1) + expect(response).to have_http_status(:unprocessable_entity) expect(response.body).to include "5X4J" end end end -end \ No newline at end of file +end diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index f50829e1f..2cd80031e 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -1,38 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -describe Users::SessionsController, :type => :controller do - before(:each) do +describe Users::SessionsController, type: :controller do + before(:each) do @request.env["devise.mapping"] = Devise.mappings[:user] end - describe '#create' do - describe 'basic auth' do - it 'accepts a correct password' do + describe "#create" do + describe "basic auth" do + it "accepts a correct password" do user = create(:user, :confirmed) - post :create, params:{user: {email: user.email, password: user.password}}, format: :json + post :create, params: {user: {email: user.email, password: user.password}}, format: :json expect(response).to have_http_status(200) - end - it 'rejects an invalid password' do + it "rejects an invalid password" do user = create(:user, :confirmed) - post :create, params:{user: {email: user.email, password: "not valid"}}, format: :json + post :create, params: {user: {email: user.email, password: "not valid"}}, format: :json expect(response).to have_http_status(401) - end - it 'throw an error if format is not :json' do - + it "throw an error if format is not :json" do user = create(:user, :confirmed) expect do - post :create, params:{user: {email: user.email, password: user.password}} + post :create, params: {user: {email: user.email, password: user.password}} end.to raise_error(ActionController::UnknownFormat) end end end -end \ No newline at end of file +end diff --git a/spec/factories/billing_plans.rb b/spec/factories/billing_plans.rb index 6e18d1cca..47d12765c 100644 --- a/spec/factories/billing_plans.rb +++ b/spec/factories/billing_plans.rb @@ -1,38 +1,36 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :billing_plan do - amount {0} - name {'Default Plan'} + amount { 0 } + name { "Default Plan" } trait :default do - end end - factory :billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat, aliases: [:billing_plan_base], parent: :billing_plan do + factory :billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat, aliases: [:billing_plan_base], parent: :billing_plan do percentage_fee { 0.025 } flat_fee { 5 } trait :with_monthly_fee do - amount {500} + amount { 500 } end trait :with_associated_stripe_plan do - transient do - stripe_plan { create(:stripe_plan_base, amount: amount || 0)} + transient do + stripe_plan { create(:stripe_plan_base, amount: amount || 0) } end - stripe_plan_id { stripe_plan.id} + stripe_plan_id { stripe_plan.id } end end factory :default_billing_plan do - end - factory :billing_plan_percentage_fee_of_1_8_percent, parent: :billing_plan do + factory :billing_plan_percentage_fee_of_1_8_percent, parent: :billing_plan do percentage_fee { 0.018 } end - factory :billing_plan_percentage_fee_of_3_8_percent, parent: :billing_plan do + factory :billing_plan_percentage_fee_of_3_8_percent, parent: :billing_plan do percentage_fee { 0.018 } end end diff --git a/spec/factories/billing_subscriptions.rb b/spec/factories/billing_subscriptions.rb index 2cdf55bce..bde3ea0ab 100644 --- a/spec/factories/billing_subscriptions.rb +++ b/spec/factories/billing_subscriptions.rb @@ -1,16 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :billing_subscription, aliases: [:billing_subscription_base] do - nonprofit {association :nonprofit_base } + nonprofit { association :nonprofit_base } billing_plan { association :billing_plan_base } trait :with_associated_stripe_subscription do - transient do - stripe_subscription {association :stripe_subscription_base, stripe_customer: stripe_customer} - stripe_customer { association :stripe_customer_base} + transient do + stripe_subscription { association :stripe_subscription_base, stripe_customer: stripe_customer } + stripe_customer { association :stripe_customer_base } end - billing_plan {association :billing_plan_base, :with_associated_stripe_plan} - stripe_subscription_id { stripe_subscription.id} - + billing_plan { association :billing_plan_base, :with_associated_stripe_plan } + stripe_subscription_id { stripe_subscription.id } end end end diff --git a/spec/factories/campaign_gift_options.rb b/spec/factories/campaign_gift_options.rb index 8c60fc302..ffd45e39b 100644 --- a/spec/factories/campaign_gift_options.rb +++ b/spec/factories/campaign_gift_options.rb @@ -1,22 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :campaign_gift_option, aliases: [:campaign_gift_option_base] do - sequence(:name) {|i| "name_#{i}"} - campaign {build(:campaign_with_things_set_1)} - amount_one_time {200} + sequence(:name) { |i| "name_#{i}" } + campaign { build(:campaign_with_things_set_1) } + amount_one_time { 200 } trait :with_one_campaign_gift do - campaign_gifts {[ - build(:campaign_gift, - donation: build(:donation_base_with_supporter, campaign:campaign, nonprofit: campaign.nonprofit) - ) - ]} + campaign_gifts { + [ + build(:campaign_gift, + donation: build(:donation_base_with_supporter, campaign: campaign, nonprofit: campaign.nonprofit)) + ] + } end trait :with_two_campaign_gifts do - campaign_gifts { - build_list(:campaign_gift, 2, donation: build(:donation_base_with_supporter, campaign:campaign, nonprofit: campaign.nonprofit)) - } + campaign_gifts { + build_list(:campaign_gift, 2, donation: build(:donation_base_with_supporter, campaign: campaign, nonprofit: campaign.nonprofit)) + } end end end diff --git a/spec/factories/campaign_gifts.rb b/spec/factories/campaign_gifts.rb index 7692a2c4c..713a50186 100644 --- a/spec/factories/campaign_gifts.rb +++ b/spec/factories/campaign_gifts.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :campaign_gift do - end end diff --git a/spec/factories/campaigns.rb b/spec/factories/campaigns.rb index 120e7363c..2e22dce21 100644 --- a/spec/factories/campaigns.rb +++ b/spec/factories/campaigns.rb @@ -3,44 +3,44 @@ factory :campaign do profile nonprofit - sequence(:name) {|i| "name #{i}"} - sequence(:slug) {|i| "slug_#{i}"} + sequence(:name) { |i| "name #{i}" } + sequence(:slug) { |i| "slug_#{i}" } factory :campaign_with_things_set_1 do - main_image { File.open('spec/fixtures/test_nonprofit_logo.png')} - background_image { File.open('spec/fixtures/test_nonprofit_logo.png')} - banner_image { File.open('spec/fixtures/test_nonprofit_logo.png')} - name {"Everything"} - slug { "a-slug-of-slugs1"} - tagline { "tagline 1"} - body { "body 1"} - video_url {"http://first-video-url.com"} - receipt_message {"receipt message 1"} - youtube_video_id { "1"} - summary {"summary1"} - goal_amount { 15000} - reason_for_supporting { 'great reason 3'} + main_image { File.open("spec/fixtures/test_nonprofit_logo.png") } + background_image { File.open("spec/fixtures/test_nonprofit_logo.png") } + banner_image { File.open("spec/fixtures/test_nonprofit_logo.png") } + name { "Everything" } + slug { "a-slug-of-slugs1" } + tagline { "tagline 1" } + body { "body 1" } + video_url { "http://first-video-url.com" } + receipt_message { "receipt message 1" } + youtube_video_id { "1" } + summary { "summary1" } + goal_amount { 15000 } + reason_for_supporting { "great reason 3" } end factory :campaign_with_things_set_2 do - main_image { File.open('spec/fixtures/test_new_nonprofit_logo.png')} - background_image { File.open('spec/fixtures/test_new_nonprofit_logo.png')} - banner_image { File.open('spec/fixtures/test_new_nonprofit_logo.png')} - name {"Everything2"} - slug { "a-slug-of-slugs2"} - tagline { "tagline 2"} - body { "body 2"} - video_url {"http://second-video-url.com"} - receipt_message {"receipt message 2"} - youtube_video_id { "2"} - summary {"summary2"} - goal_amount { 10000} - reason_for_supporting { 'great reason 1'} + main_image { File.open("spec/fixtures/test_new_nonprofit_logo.png") } + background_image { File.open("spec/fixtures/test_new_nonprofit_logo.png") } + banner_image { File.open("spec/fixtures/test_new_nonprofit_logo.png") } + name { "Everything2" } + slug { "a-slug-of-slugs2" } + tagline { "tagline 2" } + body { "body 2" } + video_url { "http://second-video-url.com" } + receipt_message { "receipt message 2" } + youtube_video_id { "2" } + summary { "summary2" } + goal_amount { 10000 } + reason_for_supporting { "great reason 1" } end - factory :empty_campaign do - goal_amount { 20000} - reason_for_supporting { 'great reason empty'} + factory :empty_campaign do + goal_amount { 20000 } + reason_for_supporting { "great reason empty" } end end end diff --git a/spec/factories/cards.rb b/spec/factories/cards.rb index 9a38bfb37..f93f57c14 100644 --- a/spec/factories/cards.rb +++ b/spec/factories/cards.rb @@ -1,21 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :card, aliases: [:active_card_1, :active_card_2, :card_base] do - name {'card 1'} + name { "card 1" } factory :inactive_card do - inactive {true} + inactive { true } end trait :with_created_stripe_customer_and_card do transient do stripe_card { association :stripe_card_base } end - stripe_card_id {stripe_card.id} - stripe_customer_id { stripe_card.customer} + stripe_card_id { stripe_card.id } + stripe_customer_id { stripe_card.customer } end trait :with_supporter do - holder { association :supporter_base} + holder { association :supporter_base } end end end diff --git a/spec/factories/charges.rb b/spec/factories/charges.rb index f6a99eb8e..562d90e46 100644 --- a/spec/factories/charges.rb +++ b/spec/factories/charges.rb @@ -1,12 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :charge do - stripe_charge_id {"ch_test_id"} + stripe_charge_id { "ch_test_id" } end - factory :charge_base, class: 'Charge' do - stripe_charge_id {"ch_test_id"} - nonprofit {supporter.nonprofit} - supporter {association :supporter_base} + factory :charge_base, class: "Charge" do + stripe_charge_id { "ch_test_id" } + nonprofit { supporter.nonprofit } + supporter { association :supporter_base } end end diff --git a/spec/factories/custom_field_joins.rb b/spec/factories/custom_field_joins.rb index e5f9908ba..fad4e969c 100644 --- a/spec/factories/custom_field_joins.rb +++ b/spec/factories/custom_field_joins.rb @@ -1,17 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :custom_field_join do - custom_field_master_id {1} - supporter_id {4} - created_at {DateTime.now} - updated_at {DateTime.now} - value {'value'} + custom_field_master_id { 1 } + supporter_id { 4 } + created_at { DateTime.now } + updated_at { DateTime.now } + value { "value" } trait :value_from_id do after(:create) do |cfj| cfj.value = "Value#{cfj.id}" end end - end end diff --git a/spec/factories/custom_field_masters.rb b/spec/factories/custom_field_masters.rb index f184d2ad6..c9043a02a 100644 --- a/spec/factories/custom_field_masters.rb +++ b/spec/factories/custom_field_masters.rb @@ -2,6 +2,6 @@ FactoryBot.define do factory :custom_field_master do nonprofit {} - name {"MyString"} + name { "MyString" } end end diff --git a/spec/factories/direct_debit_details.rb b/spec/factories/direct_debit_details.rb index 1c170277b..1fe5414f5 100644 --- a/spec/factories/direct_debit_details.rb +++ b/spec/factories/direct_debit_details.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :direct_debit_detail do - end end diff --git a/spec/factories/dispute_payment_backups.rb b/spec/factories/dispute_payment_backups.rb index f926aff58..6508a1ccb 100644 --- a/spec/factories/dispute_payment_backups.rb +++ b/spec/factories/dispute_payment_backups.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :dispute_payment_backup do - end end diff --git a/spec/factories/dispute_transactions.rb b/spec/factories/dispute_transactions.rb index 685cac466..59341b8fc 100644 --- a/spec/factories/dispute_transactions.rb +++ b/spec/factories/dispute_transactions.rb @@ -1,13 +1,13 @@ FactoryBot.define do factory :dispute_transaction, aliases: [:dispute_transaction_base] do - disbursed {false} + disbursed { false } trait :from_donation do - dispute{ build(:dispute, charge: build(:charge_base, payment: build(:payment, donation: build(:donation))))} + dispute { build(:dispute, charge: build(:charge_base, payment: build(:payment, donation: build(:donation)))) } end trait :not_from_donation do - dispute{ build(:dispute, charge: build(:charge_base, payment: build(:payment)))} + dispute { build(:dispute, charge: build(:charge_base, payment: build(:payment))) } end end end diff --git a/spec/factories/disputes.rb b/spec/factories/disputes.rb index 9e00c0364..6ffe45d31 100644 --- a/spec/factories/disputes.rb +++ b/spec/factories/disputes.rb @@ -1,9 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :dispute do - stripe_dispute_id {"dp_05RsQX2eZvKYlo2C0FRTGSSA"} # the default dispute + stripe_dispute_id { "dp_05RsQX2eZvKYlo2C0FRTGSSA" } # the default dispute trait :autocreate_dispute do - sequence(:stripe_dispute_id, 'a') {|i| "dp_05RsQX2eZvKYlo2C0FRTGSS" + i} + sequence(:stripe_dispute_id, "a") { |i| "dp_05RsQX2eZvKYlo2C0FRTGSS" + i } end end end diff --git a/spec/factories/donations.rb b/spec/factories/donations.rb index b80679882..348ff1527 100644 --- a/spec/factories/donations.rb +++ b/spec/factories/donations.rb @@ -3,60 +3,66 @@ factory :donation do end - factory :donation_base, class: 'Donation' do - nonprofit {supporter.nonprofit} - amount {333} - factory :donation_base_with_supporter, class: 'Donation' do - supporter {build(:supporter_base)} + factory :donation_base, class: "Donation" do + nonprofit { supporter.nonprofit } + amount { 333 } + factory :donation_base_with_supporter, class: "Donation" do + supporter { build(:supporter_base) } end trait :and_campaign_gift do - campaign { build(:campaign_with_things_set_1, nonprofit: nonprofit)} - campaign_gifts {[ - build( - :campaign_gift, - campaign_gift_option:build( - :campaign_gift_option, + campaign { build(:campaign_with_things_set_1, nonprofit: nonprofit) } + campaign_gifts { + [ + build( + :campaign_gift, + campaign_gift_option: build( + :campaign_gift_option, campaign: campaign + ) ) - )] + ] } end factory :donation_with_dedication do - dedication { { - contact: { - email: 'email@ema.com', - phone: '234-343-3234', - address: '123 Four' - }, - name: 'our loved one', - note: 'we miss them dearly', - type: 'memory' - }.to_json } + dedication { + { + contact: { + email: "email@ema.com", + phone: "234-343-3234", + address: "123 Four" + }, + name: "our loved one", + note: "we miss them dearly", + type: "memory" + }.to_json + } end end - factory :fv_poverty_donation, class: 'Donation' do - nonprofit {association :fv_poverty} + factory :fv_poverty_donation, class: "Donation" do + nonprofit { association :fv_poverty } - supporter { build(:supporter_with_fv_poverty, nonprofit: nonprofit)} - amount {333} - factory :donation_with_dedication_designation do - dedication { { - contact: { - email: 'email@ema.com' - }, - name: 'our loved one', - note: "we miss them dearly", - type: 'memory' - } } - designation { 'designated for soup kitchen'} + supporter { build(:supporter_with_fv_poverty, nonprofit: nonprofit) } + amount { 333 } + factory :donation_with_dedication_designation do + dedication { + { + contact: { + email: "email@ema.com" + }, + name: "our loved one", + note: "we miss them dearly", + type: "memory" + } + } + designation { "designated for soup kitchen" } - nonprofit {association :fv_poverty} + nonprofit { association :fv_poverty } - supporter { association :supporter} - amount {500} + supporter { association :supporter } + amount { 500 } end end end diff --git a/spec/factories/drip_email_lists.rb b/spec/factories/drip_email_lists.rb index 55f9aead5..b6532d51d 100644 --- a/spec/factories/drip_email_lists.rb +++ b/spec/factories/drip_email_lists.rb @@ -4,7 +4,7 @@ factory :drip_email_list do end - factory :drip_email_list_base, class: 'DripEmailList' do - sequence(:mailchimp_list_id) {|i| "mailchimp_list_id#{i}"} - end + factory :drip_email_list_base, class: "DripEmailList" do + sequence(:mailchimp_list_id) { |i| "mailchimp_list_id#{i}" } + end end diff --git a/spec/factories/e_tap_import_journal_entries.rb b/spec/factories/e_tap_import_journal_entries.rb index 21c4fcbc9..13720ddf1 100644 --- a/spec/factories/e_tap_import_journal_entries.rb +++ b/spec/factories/e_tap_import_journal_entries.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :e_tap_import_journal_entry do - end end diff --git a/spec/factories/e_tap_imports.rb b/spec/factories/e_tap_imports.rb index 722f4abaf..90bab34bc 100644 --- a/spec/factories/e_tap_imports.rb +++ b/spec/factories/e_tap_imports.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :e_tap_import do - end end diff --git a/spec/factories/email_customizations.rb b/spec/factories/email_customizations.rb index a09adf702..6001edea8 100644 --- a/spec/factories/email_customizations.rb +++ b/spec/factories/email_customizations.rb @@ -3,6 +3,6 @@ factory :email_customization do name { "name" } contents { "email customization contents" } - nonprofit {association :nonprofit_base} + nonprofit { association :nonprofit_base } end end diff --git a/spec/factories/email_lists.rb b/spec/factories/email_lists.rb index d766b921c..4d797aec2 100644 --- a/spec/factories/email_lists.rb +++ b/spec/factories/email_lists.rb @@ -2,17 +2,15 @@ factory :email_list do end - factory :email_list_base, class: 'EmailList' do - sequence(:list_name) {|i|"list_name#{i}"} - sequence(:mailchimp_list_id) {|i| "mailchimp_list_id#{i}"} - tag_master {build(:tag_master_base)} - nonprofit { association :nonprofit_base} - base_uri { 'https://us3.api.mailchimp.com/3.0'} + factory :email_list_base, class: "EmailList" do + sequence(:list_name) { |i| "list_name#{i}" } + sequence(:mailchimp_list_id) { |i| "mailchimp_list_id#{i}" } + tag_master { build(:tag_master_base) } + nonprofit { association :nonprofit_base } + base_uri { "https://us3.api.mailchimp.com/3.0" } trait :without_base_uri do base_uri { nil } end end - - end diff --git a/spec/factories/events.rb b/spec/factories/events.rb index 8383ddc33..0f116618c 100644 --- a/spec/factories/events.rb +++ b/spec/factories/events.rb @@ -1,13 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :event do - name {"The event of Wonders"} - start_datetime {DateTime.new(2025, 5, 11, 4,5,6)} - end_datetime {DateTime.new(2025, 5, 11, 5,1,7)} - address {"100 N Appleton St"} - city {"Appleton"} - state_code {"WI"} - slug {"event-of-wonders"} + name { "The event of Wonders" } + start_datetime { DateTime.new(2025, 5, 11, 4, 5, 6) } + end_datetime { DateTime.new(2025, 5, 11, 5, 1, 7) } + address { "100 N Appleton St" } + city { "Appleton" } + state_code { "WI" } + slug { "event-of-wonders" } nonprofit profile end @@ -16,14 +16,14 @@ transient do perform_geocode { false } end - sequence(:name){|i| "The event of Wonders #{i}"} - start_datetime {Time.current + 2.days} - end_datetime {Time.current + 2.days + 3.hours} - address {"100 N Appleton St"} - city {"Appleton"} - state_code {"WI"} - sequence(:slug){|i| "event-of-wonders-#{i}"} - nonprofit {association :nonprofit_base} + sequence(:name) { |i| "The event of Wonders #{i}" } + start_datetime { 2.days.from_now } + end_datetime { 2.days.from_now + 3.hours } + address { "100 N Appleton St" } + city { "Appleton" } + state_code { "WI" } + sequence(:slug) { |i| "event-of-wonders-#{i}" } + nonprofit { association :nonprofit_base } profile before(:create) do |event, context| diff --git a/spec/factories/fee_coverage_detail_bases.rb b/spec/factories/fee_coverage_detail_bases.rb index c0f64475e..d8a0bf396 100644 --- a/spec/factories/fee_coverage_detail_bases.rb +++ b/spec/factories/fee_coverage_detail_bases.rb @@ -1,12 +1,12 @@ FactoryBot.define do factory :fee_coverage_detail_base do - flat_fee {30} - percentage_fee {"0.022"} + flat_fee { 30 } + percentage_fee { "0.022" } end - factory :dont_consider_billing_plan_fee_coverage_detail_base, class: 'FeeCoverageDetailBase' do - flat_fee {0} - percentage_fee {"0.05"} - dont_consider_billing_plan {true} + factory :dont_consider_billing_plan_fee_coverage_detail_base, class: "FeeCoverageDetailBase" do + flat_fee { 0 } + percentage_fee { "0.05" } + dont_consider_billing_plan { true } end end diff --git a/spec/factories/fee_eras.rb b/spec/factories/fee_eras.rb index 41b877190..c200088a0 100644 --- a/spec/factories/fee_eras.rb +++ b/spec/factories/fee_eras.rb @@ -1,24 +1,23 @@ FactoryBot.define do - factory :fee_era do - start_time {"2020-05-01"} - end_time {"2020-05-07"} - local_country { 'US'} - international_surcharge_fee {'0.01'} + start_time { "2020-05-01" } + end_time { "2020-05-07" } + local_country { "US" } + international_surcharge_fee { "0.01" } fee_coverage_detail_base - factory :fee_era_with_structures, aliases: [:current_fee_era_with_structures], class: 'FeeEra' do + factory :fee_era_with_structures, aliases: [:current_fee_era_with_structures], class: "FeeEra" do after(:create) do |fee_era| fee_era.fee_structures = [build(:visa_fee_structure_base), - build(:amex_fee_structure_base), - build(:brandless_fee_structure_base)] + build(:amex_fee_structure_base), + build(:brandless_fee_structure_base)] fee_era.save! fee_era.reload end end end - factory :fee_era_with_no_start , class: 'FeeEra' do - end_time {'2020-05-01'} + factory :fee_era_with_no_start, class: "FeeEra" do + end_time { "2020-05-01" } refund_stripe_fee { true } fee_coverage_detail_base after(:create) do |fee_era| @@ -27,28 +26,25 @@ fee_era.save! fee_era.reload end - end - factory :fee_era_with_no_end, aliases: [:fee_era_local_to_us], class: 'FeeEra' do - start_time {'2020-05-07'} - local_country { 'US'} - international_surcharge_fee {'0.01'} + factory :fee_era_with_no_end, aliases: [:fee_era_local_to_us], class: "FeeEra" do + start_time { "2020-05-07" } + local_country { "US" } + international_surcharge_fee { "0.01" } fee_coverage_detail_base after(:create) do |fee_era| fee_era.fee_structures = [ build(:amex_fee_structure_base), build(:brandless_fee_structure_base) - ] - fee_era.save! - fee_era.reload + ] + fee_era.save! + fee_era.reload end end factory :fee_era_base do fee_coverage_detail_base - start_time {"2020-05-01"} + start_time { "2020-05-01" } end - - end diff --git a/spec/factories/fee_structures.rb b/spec/factories/fee_structures.rb index fcc65d130..bb0a2cc05 100644 --- a/spec/factories/fee_structures.rb +++ b/spec/factories/fee_structures.rb @@ -1,43 +1,43 @@ FactoryBot.define do - factory :visa_fee_structure_base, class: 'FeeStructure' do - flat_fee {25} - stripe_fee {BigDecimal("0.03")} - brand { "Visa"} + factory :visa_fee_structure_base, class: "FeeStructure" do + flat_fee { 25 } + stripe_fee { BigDecimal("0.03") } + brand { "Visa" } end factory :visa_fee_structure, aliases: [:countryless_fee_structure], parent: :visa_fee_structure_base do association :fee_era - - factory :local_to_us_visa_fee_structure, aliases: [:us_local_fee_structure] do - fee_era{ association :fee_era_local_to_us } + + factory :local_to_us_visa_fee_structure, aliases: [:us_local_fee_structure] do + fee_era { association :fee_era_local_to_us } end end - factory :amex_fee_structure_base, class: 'FeeStructure' do - flat_fee {0} - stripe_fee {BigDecimal("0.035")} - brand { "American Express"} + factory :amex_fee_structure_base, class: "FeeStructure" do + flat_fee { 0 } + stripe_fee { BigDecimal("0.035") } + brand { "American Express" } end factory :amex_fee_structure, parent: :amex_fee_structure_base do association :fee_era - - factory :local_to_us_amex_fee_structure do - fee_era{ association :fee_era_local_to_us} + + factory :local_to_us_amex_fee_structure do + fee_era { association :fee_era_local_to_us } end end - factory :brandless_fee_structure_base, class: 'FeeStructure' do - flat_fee {30} - stripe_fee {BigDecimal("0.022")} - brand { nil} + factory :brandless_fee_structure_base, class: "FeeStructure" do + flat_fee { 30 } + stripe_fee { BigDecimal("0.022") } + brand { nil } end - + factory :brandless_fee_structure, parent: :brandless_fee_structure_base do association :fee_era - factory :no_international_fees_brandless_fee_structure do - fee_era{association :fee_era_with_no_start} + factory :no_international_fees_brandless_fee_structure do + fee_era { association :fee_era_with_no_start } end end end diff --git a/spec/factories/json_expectations/payments.rb b/spec/factories/json_expectations/payments.rb index a232a4524..2f89efaee 100644 --- a/spec/factories/json_expectations/payments.rb +++ b/spec/factories/json_expectations/payments.rb @@ -1,36 +1,33 @@ - FactoryBot.define do - factory :payment_expectation, class: "OpenStruct" do transient do gross_amount_cents { 500 } - currency { 'usd'} - fee_total_cents { 0} + currency { "usd" } + fee_total_cents { 0 } end - - transaction {match_houid(:trx)} - nonprofit {match_houid(:np)} - supporter { match_houid(:supp)} + transaction { match_houid(:trx) } + nonprofit { match_houid(:np) } + supporter { match_houid(:supp) } - type {'payment'} + type { "payment" } created { Time.current.to_i } - gross_amount { {cents: gross_amount_cents, currency:currency}} + gross_amount { {cents: gross_amount_cents, currency: currency} } fee_total { {cents: fee_total_cents, currency: currency} } - net_amount { {cents: gross_amount_cents + fee_total_cents, currency: currency}} + net_amount { {cents: gross_amount_cents + fee_total_cents, currency: currency} } - trait :offline_transaction_charge do - object { 'offline_transaction_charge'} - id { match_houid(:offtrxchrg)} - subtransaction { match_houid(:offlinetrx)} + trait :offline_transaction_charge do + object { "offline_transaction_charge" } + id { match_houid(:offtrxchrg) } + subtransaction { match_houid(:offlinetrx) } end - trait :stripe_transaction_charge do - object { 'stripe_transaction_charge'} - id { match_houid(:stripechrg)} + trait :stripe_transaction_charge do + object { "stripe_transaction_charge" } + id { match_houid(:stripechrg) } legacy_id { be_a_kind_of(Numeric) } legacy_nonprofit { be_a_kind_of(Numeric) } - subtransaction { match_houid(:stripetrx)} + subtransaction { match_houid(:stripetrx) } end end -end \ No newline at end of file +end diff --git a/spec/factories/json_expectations/subtransactions.rb b/spec/factories/json_expectations/subtransactions.rb index b57631cdf..d2e5f5895 100644 --- a/spec/factories/json_expectations/subtransactions.rb +++ b/spec/factories/json_expectations/subtransactions.rb @@ -1,35 +1,30 @@ - FactoryBot.define do factory :subtransaction_expectation, class: "OpenStruct" do - transient do gross_amount_cents { 500 } - currency { 'usd'} - net_amount_cents {500} + currency { "usd" } + net_amount_cents { 500 } end - - transaction {match_houid(:trx)} - nonprofit {match_houid(:np)} - supporter { match_houid(:supp)} - - + transaction { match_houid(:trx) } + nonprofit { match_houid(:np) } + supporter { match_houid(:supp) } - type {'subtransaction'} + type { "subtransaction" } created { Time.current.to_i } - amount { {cents: gross_amount_cents, currency:currency}} - net_amount { {cents: net_amount_cents, currency: currency}} + amount { {cents: gross_amount_cents, currency: currency} } + net_amount { {cents: net_amount_cents, currency: currency} } trait :offline_transaction do - object {'offline_transaction'} - id { match_houid(:offlinetrx)} - payments { [match_houid(:offtrxchrg)]} + object { "offline_transaction" } + id { match_houid(:offlinetrx) } + payments { [match_houid(:offtrxchrg)] } end trait :stripe_transaction do - object {'stripe_transaction'} - id { match_houid(:stripetrx)} - payments { [match_houid(:stripechrg)]} + object { "stripe_transaction" } + id { match_houid(:stripetrx) } + payments { [match_houid(:stripechrg)] } end end -end \ No newline at end of file +end diff --git a/spec/factories/json_expectations/supporter_addresses.rb b/spec/factories/json_expectations/supporter_addresses.rb index c83f76730..1fd790423 100644 --- a/spec/factories/json_expectations/supporter_addresses.rb +++ b/spec/factories/json_expectations/supporter_addresses.rb @@ -1,10 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :supporter_address_expectations, class: "OpenStruct" do - - - - - end -end \ No newline at end of file +end diff --git a/spec/factories/json_expectations/supporters.rb b/spec/factories/json_expectations/supporters.rb index 03500ff1c..27106da93 100644 --- a/spec/factories/json_expectations/supporters.rb +++ b/spec/factories/json_expectations/supporters.rb @@ -1,13 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :supporter_expectation, class: "OpenStruct" do - id { match_houid(:supp) } legacy_id { be_a_kind_of(Numeric) } legacy_nonprofit { be_a_kind_of(Numeric) } - deleted {false} - object {'supporter'} - - + deleted { false } + object { "supporter" } end -end \ No newline at end of file +end diff --git a/spec/factories/json_expectations/transactions.rb b/spec/factories/json_expectations/transactions.rb index 37e38d4b3..bd95bce40 100644 --- a/spec/factories/json_expectations/transactions.rb +++ b/spec/factories/json_expectations/transactions.rb @@ -1,25 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :trx, class: "OpenStruct" do - transient do amount_cents { 500 } - currency { 'usd'} - + currency { "usd" } end - nonprofit { match_houid(:np)} - id {match_houid(:trx)} - supporter { match_houid(:supp)} - #created { Time.current.to_i } - amount { {cents: amount_cents, currency:currency}} - object {'transaction'} + nonprofit { match_houid(:np) } + id { match_houid(:trx) } + supporter { match_houid(:supp) } + # created { Time.current.to_i } + amount { {cents: amount_cents, currency: currency} } + object { "transaction" } - trait :concrete do + trait :concrete do # a set of properties that don't do matching but make this a concrete example - nonprofit {"np_JMR7tipP7swuk0Kxk2RBss"} - id {"trx_gSxbMtyNaDnQKgwF1kzzit"} - supporter { "supp_8SE0GLbbsJWJ5jOpACG4Fu"} + nonprofit { "np_JMR7tipP7swuk0Kxk2RBss" } + id { "trx_gSxbMtyNaDnQKgwF1kzzit" } + supporter { "supp_8SE0GLbbsJWJ5jOpACG4Fu" } end end -end \ No newline at end of file +end diff --git a/spec/factories/json_expectations/trx_assignments.rb b/spec/factories/json_expectations/trx_assignments.rb index da45a27f2..31e2ffcbc 100644 --- a/spec/factories/json_expectations/trx_assignments.rb +++ b/spec/factories/json_expectations/trx_assignments.rb @@ -1,24 +1,21 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :trx_assignment_expectation, class: "OpenStruct" do - transient do amount_cents { 500 } - currency { 'usd'} - + currency { "usd" } end - - transaction {match_houid(:trx)} - nonprofit {match_houid(:np)} - supporter { match_houid(:supp)} + transaction { match_houid(:trx) } + nonprofit { match_houid(:np) } + supporter { match_houid(:supp) } - type {'trx_assignment'} - amount { {cents: amount_cents, currency:currency}} + type { "trx_assignment" } + amount { {cents: amount_cents, currency: currency} } trait :donation do - id { match_houid(:don)} - object {'donation'} + id { match_houid(:don) } + object { "donation" } end end -end \ No newline at end of file +end diff --git a/spec/factories/manual_balance_adjustments.rb b/spec/factories/manual_balance_adjustments.rb index 8fca85817..df9de3153 100644 --- a/spec/factories/manual_balance_adjustments.rb +++ b/spec/factories/manual_balance_adjustments.rb @@ -4,7 +4,7 @@ gross_amount { 0 } trait :with_entity_and_payment do - entity {create(:charge_base)} + entity { create(:charge_base) } end end end diff --git a/spec/factories/misc_event_infos.rb b/spec/factories/misc_event_infos.rb index 32d674ac1..d69417e18 100644 --- a/spec/factories/misc_event_infos.rb +++ b/spec/factories/misc_event_infos.rb @@ -1,5 +1,5 @@ FactoryBot.define do factory :misc_event_info do - hide_cover_fees_option {false} + hide_cover_fees_option { false } end end diff --git a/spec/factories/misc_payment_infos.rb b/spec/factories/misc_payment_infos.rb index 5cae4e11a..21c3f6809 100644 --- a/spec/factories/misc_payment_infos.rb +++ b/spec/factories/misc_payment_infos.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :misc_payment_info do - end end diff --git a/spec/factories/misc_recurring_donation_infos.rb b/spec/factories/misc_recurring_donation_infos.rb index 42ba6f34b..d6b60421e 100644 --- a/spec/factories/misc_recurring_donation_infos.rb +++ b/spec/factories/misc_recurring_donation_infos.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :misc_recurring_donation_info do - end end diff --git a/spec/factories/misc_refund_infos.rb b/spec/factories/misc_refund_infos.rb index a8b2aed20..ba41d64a0 100644 --- a/spec/factories/misc_refund_infos.rb +++ b/spec/factories/misc_refund_infos.rb @@ -1,5 +1,5 @@ FactoryBot.define do factory :misc_refund_info do - is_modern {false} + is_modern { false } end end diff --git a/spec/factories/miscellaneous_np_infos.rb b/spec/factories/miscellaneous_np_infos.rb index 5aef4bed9..657d76e65 100644 --- a/spec/factories/miscellaneous_np_infos.rb +++ b/spec/factories/miscellaneous_np_infos.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :miscellaneous_np_info do - end end diff --git a/spec/factories/modern_donations.rb b/spec/factories/modern_donations.rb index 56a5f6cf2..da39903e1 100644 --- a/spec/factories/modern_donations.rb +++ b/spec/factories/modern_donations.rb @@ -6,11 +6,10 @@ factory :modern_donation do amount { 4000 } end - + factory :modern_donation_base, class: "ModernDonation" do amount { legacy_donation.payments.first.gross_amount } end - end diff --git a/spec/factories/nonprofit_deactivations.rb b/spec/factories/nonprofit_deactivations.rb index cc023bf67..d510af222 100644 --- a/spec/factories/nonprofit_deactivations.rb +++ b/spec/factories/nonprofit_deactivations.rb @@ -1,5 +1,5 @@ FactoryBot.define do factory :nonprofit_deactivation do - deactivated {false} + deactivated { false } end end diff --git a/spec/factories/nonprofit_keys.rb b/spec/factories/nonprofit_keys.rb index fb7cb31fe..58baf4253 100644 --- a/spec/factories/nonprofit_keys.rb +++ b/spec/factories/nonprofit_keys.rb @@ -2,6 +2,6 @@ FactoryBot.define do factory :nonprofit_key do nonprofit - mailchimp_token {'a token'} + mailchimp_token { "a token" } end end diff --git a/spec/factories/nonprofit_s3_keys.rb b/spec/factories/nonprofit_s3_keys.rb index e689dad9d..38794ec0d 100644 --- a/spec/factories/nonprofit_s3_keys.rb +++ b/spec/factories/nonprofit_s3_keys.rb @@ -1,9 +1,9 @@ FactoryBot.define do factory :nonprofit_s3_key do - nonprofit { association :nonprofit_base} + nonprofit { association :nonprofit_base } access_key_id { "MyString" } secret_access_key { "MyString" } bucket_name { "MyString" } - region {"ci-estn-1"} + region { "ci-estn-1" } end end diff --git a/spec/factories/nonprofit_verification_process_statuses.rb b/spec/factories/nonprofit_verification_process_statuses.rb index 334f49d94..d604a129c 100644 --- a/spec/factories/nonprofit_verification_process_statuses.rb +++ b/spec/factories/nonprofit_verification_process_statuses.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :nonprofit_verification_process_status do - end end diff --git a/spec/factories/nonprofits.rb b/spec/factories/nonprofits.rb index d7f881992..c2c709b41 100644 --- a/spec/factories/nonprofits.rb +++ b/spec/factories/nonprofits.rb @@ -1,65 +1,63 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :nonprofit do - name {"spec_nonprofit_full"} - city {'Albuquerque'} - state_code {'NM'} - zip_code {55555} - email {"example@email.com"} - slug {'sluggy-sluggo'} - billing_subscription {build(:billing_subscription, billing_plan: build(:billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat))} + name { "spec_nonprofit_full" } + city { "Albuquerque" } + state_code { "NM" } + zip_code { 55555 } + email { "example@email.com" } + slug { "sluggy-sluggo" } + billing_subscription { build(:billing_subscription, billing_plan: build(:billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)) } vetted { true } factory :nonprofit_with_cards do - after(:create) {|nonprofit, evaluator| - create(:active_card_1, holder:nonprofit) - create(:active_card_2, holder:nonprofit) - create(:inactive_card, holder:nonprofit) + after(:create) { |nonprofit, evaluator| + create(:active_card_1, holder: nonprofit) + create(:active_card_2, holder: nonprofit) + create(:inactive_card, holder: nonprofit) } end - factory :nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat do - + factory :nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat do end - factory :nonprofit_with_billing_plan_percentage_fee_of_2_5_with_fee_era do - + factory :nonprofit_with_billing_plan_percentage_fee_of_2_5_with_fee_era do end - factory :nonprofit_with_no_billing_subscription do - billing_subscription { nil} + factory :nonprofit_with_no_billing_subscription do + billing_subscription { nil } end factory :nonprofit_with_activated_deactivation_record do - nonprofit_deactivation { build(:nonprofit_deactivation, deactivated: false)} + nonprofit_deactivation { build(:nonprofit_deactivation, deactivated: false) } end factory :nonprofit_with_deactivated_deactivation_record do - nonprofit_deactivation { build(:nonprofit_deactivation, deactivated: true)} + nonprofit_deactivation { build(:nonprofit_deactivation, deactivated: true) } end end factory :fv_poverty, class: Nonprofit do id { 22352 } - name { 'Ending Poverty in the Fox Valley Inc.' } - city { 'Appleton' } - state_code { 'WI' } + name { "Ending Poverty in the Fox Valley Inc." } + city { "Appleton" } + state_code { "WI" } zip_code { 54915 } - email { 'contact@endpovertyinthefoxvalleyinc.org' } - website {'https://endpovertyinthefoxvalleyinc.org'} + email { "contact@endpovertyinthefoxvalleyinc.org" } + website { "https://endpovertyinthefoxvalleyinc.org" } sequence(:slug) { |n| "#{n}-end-poverty-in-the-fox-valley-inc" } - state_code_slug { 'wi'} - city_slug { 'appleton'} - billing_subscription {build(:billing_subscription, billing_plan: build(:billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat))} + state_code_slug { "wi" } + city_slug { "appleton" } + billing_subscription { build(:billing_subscription, billing_plan: build(:billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)) } end - factory :nonprofit_base, class: 'Nonprofit' do - name { 'Ending Poverty in the Fox Valley Inc.' } - city { 'Appleton '} - state_code { 'wi'} + factory :nonprofit_base, class: "Nonprofit" do + name { "Ending Poverty in the Fox Valley Inc." } + city { "Appleton " } + state_code { "wi" } sequence(:slug) { |n| "#{n}-end-poverty-in-the-fox-valley-inc" } - state_code_slug { 'wi'} - city_slug { 'appleton'} + state_code_slug { "wi" } + city_slug { "appleton" } trait :activated_deactivation_record do nonprofit_deactivation { association :nonprofit_deactivation, deactivated: false } @@ -73,8 +71,7 @@ end trait :with_active_card_on_stripe do - active_card {association :card_base, :with_created_stripe_customer_and_card} - + active_card { association :card_base, :with_created_stripe_customer_and_card } end trait :with_billing_subscription_on_stripe do @@ -82,25 +79,24 @@ billing_plan {} end with_active_card_on_stripe - billing_subscription { + billing_subscription { attributes = { - + stripe_customer: active_card.stripe_customer } if billing_plan attributes[:billing_plan] = billing_plan end - association :billing_subscription, - :with_associated_stripe_subscription, - nonprofit: @instance, - **attributes - } + association :billing_subscription, + :with_associated_stripe_subscription, + nonprofit: @instance, + **attributes + } end - trait :with_inactive_tag do after(:create) do |nonprofit, evaluator| - nonprofit.tag_masters << build(:tag_master_base, deleted:true) + nonprofit.tag_masters << build(:tag_master_base, deleted: true) nonprofit.save end end @@ -114,28 +110,26 @@ trait :with_active_mailing_list do after(:create) do |nonprofit, evaluator| - nonprofit.tag_masters << build(:tag_master_base, :with_email_list, nonprofit:nonprofit) + nonprofit.tag_masters << build(:tag_master_base, :with_email_list, nonprofit: nonprofit) nonprofit.save end end trait :with_inactive_mailing_list do after(:create) do |nonprofit, evaluator| - nonprofit.tag_masters << build(:tag_master_base, :with_email_list, deleted:true, nonprofit:nonprofit) + nonprofit.tag_masters << build(:tag_master_base, :with_email_list, deleted: true, nonprofit: nonprofit) nonprofit.save end end trait :with_old_billing_plan_on_stripe do - with_active_card_on_stripe - billing_subscription { association :billing_subscription, - :with_associated_stripe_subscription, - stripe_customer: active_card.stripe_customer, - billing_plan: create(:billing_plan_base, :with_associated_stripe_plan, amount: 133333, percentage_fee: 0.33, name: "fake plan") + billing_subscription { + association :billing_subscription, + :with_associated_stripe_subscription, + stripe_customer: active_card.stripe_customer, + billing_plan: create(:billing_plan_base, :with_associated_stripe_plan, amount: 133333, percentage_fee: 0.33, name: "fake plan") } end - - end end diff --git a/spec/factories/object_events.rb b/spec/factories/object_events.rb index 75e107fd0..19c644fd2 100644 --- a/spec/factories/object_events.rb +++ b/spec/factories/object_events.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :object_event do - end end diff --git a/spec/factories/offline_transaction_charges.rb b/spec/factories/offline_transaction_charges.rb index 453726aad..dc212e5de 100644 --- a/spec/factories/offline_transaction_charges.rb +++ b/spec/factories/offline_transaction_charges.rb @@ -3,7 +3,6 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE FactoryBot.define do - factory :offline_transaction_charge, aliases: [:offline_transaction_charge_base] do - - end + factory :offline_transaction_charge, aliases: [:offline_transaction_charge_base] do + end end diff --git a/spec/factories/offline_transactions.rb b/spec/factories/offline_transactions.rb index 72bf20576..683619aa8 100644 --- a/spec/factories/offline_transactions.rb +++ b/spec/factories/offline_transactions.rb @@ -3,22 +3,21 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE FactoryBot.define do - factory :offline_transaction do - amount { 4000 } - end + factory :offline_transaction do + amount { 4000 } + end - factory :offline_transaction_for_testing_payment_extensions, class: 'OfflineTransaction' do - transient do - currency {'fake'} - end + factory :offline_transaction_for_testing_payment_extensions, class: "OfflineTransaction" do + transient do + currency { "fake" } + end - amount {707} + amount { 707 } - subtransaction{build(:subtransaction_for_testing_payment_extensions)} - end - - factory :offline_transaction_base, class: 'OfflineTransaction' do - amount { 333 } - end + subtransaction { build(:subtransaction_for_testing_payment_extensions) } + end + factory :offline_transaction_base, class: "OfflineTransaction" do + amount { 333 } + end end diff --git a/spec/factories/offsite_payments.rb b/spec/factories/offsite_payments.rb index fc0efc867..c99d6402c 100644 --- a/spec/factories/offsite_payments.rb +++ b/spec/factories/offsite_payments.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :offsite_payment do - end - factory :offsite_payment_base, class: 'OffsitePayment' do - payment { association :legacy_payment_base, :with_offline_donation, offsite_payment: @instance} - supporter { association :supporter_base} - nonprofit { supporter.nonprofit} + factory :offsite_payment_base, class: "OffsitePayment" do + payment { association :legacy_payment_base, :with_offline_donation, offsite_payment: @instance } + supporter { association :supporter_base } + nonprofit { supporter.nonprofit } end end diff --git a/spec/factories/payment_dupe_statuses.rb b/spec/factories/payment_dupe_statuses.rb index b27f1f45d..1a471c4d9 100644 --- a/spec/factories/payment_dupe_statuses.rb +++ b/spec/factories/payment_dupe_statuses.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :payment_dupe_status do - payment_id {1} - matched {false} + payment_id { 1 } + matched { false } end end diff --git a/spec/factories/payment_imports.rb b/spec/factories/payment_imports.rb index 901c06a45..952750c6a 100644 --- a/spec/factories/payment_imports.rb +++ b/spec/factories/payment_imports.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :payment_import do - end end diff --git a/spec/factories/payment_payouts.rb b/spec/factories/payment_payouts.rb index 122259f66..c262c4a55 100644 --- a/spec/factories/payment_payouts.rb +++ b/spec/factories/payment_payouts.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :payment_payout do - end end diff --git a/spec/factories/payments.rb b/spec/factories/payments.rb index b524d2ea5..f99c972b4 100644 --- a/spec/factories/payments.rb +++ b/spec/factories/payments.rb @@ -1,75 +1,75 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do trait :with_offline_payment do - offsite_payment { association :offsite_payment_base, + offsite_payment { + association :offsite_payment_base, nonprofit: nonprofit, supporter: supporter, gross_amount: gross_amount, payment: @instance - } + } end trait :with_offline_donation do with_offline_payment - donation { build(:donation_base, supporter: supporter, payments: [@instance])} + donation { build(:donation_base, supporter: supporter, payments: [@instance]) } end factory :payment, aliases: [:payment_base, :legacy_payment_base] do - supporter {association :supporter_base} - nonprofit {supporter.nonprofit} + supporter { association :supporter_base } + nonprofit { supporter.nonprofit } gross_amount { 333 } - fee_total {0} - net_amount { gross_amount + fee_total} + fee_total { 0 } + net_amount { gross_amount + fee_total } end factory :payment_generator_with_id, class: "Payment" do transient do - amount { 100 + Random.rand(5000)} - + amount { Random.rand(100..5099) } end sequence(:id) - gross_amount { amount} + gross_amount { amount } supporter - date { Faker::Time.between(from: Time.current.beginning_of_year, to: Time.current.end_of_year)} + date { Faker::Time.between(from: Time.current.beginning_of_year, to: Time.current.end_of_year) } before(:create) do |payment| payment.id = nil if payment.id end factory :donation_payment_generator do - donation { association :donation, amount: amount, supporter: supporter, nonprofit: nonprofit, created_at: date} + donation { association :donation, amount: amount, supporter: supporter, nonprofit: nonprofit, created_at: date } end factory :refund_payment_generator do - refund { association :refund_base, amount: amount * -1, created_at: date} + refund { association :refund_base, amount: amount * -1, created_at: date } gross_amount { amount * -1 } end - + factory :dispute_payment_generator do - dispute_transaction { association :dispute_transaction_base, created_at: date} + dispute_transaction { association :dispute_transaction_base, created_at: date } end factory :dispute_reversal_payment_generator do - dispute_transaction { association :dispute_transaction_base, created_at: date} + dispute_transaction { association :dispute_transaction_base, created_at: date } gross_amount { amount * -1 } end end factory :fv_poverty_payment, class: "Payment" do - donation {build(:fv_poverty_donation, nonprofit: nonprofit, supporter: supporter) } - gross_amount { 333} - net_amount { 333} - nonprofit { association :fv_poverty} - supporter { build(:supporter_with_fv_poverty, nonprofit: nonprofit)} + donation { build(:fv_poverty_donation, nonprofit: nonprofit, supporter: supporter) } + gross_amount { 333 } + net_amount { 333 } + nonprofit { association :fv_poverty } + supporter { build(:supporter_with_fv_poverty, nonprofit: nonprofit) } - trait :anonymous_through_donation do - donation {build(:fv_poverty_donation, nonprofit: nonprofit, supporter: supporter, anonymous:true) } + trait :anonymous_through_donation do + donation { build(:fv_poverty_donation, nonprofit: nonprofit, supporter: supporter, anonymous: true) } end - trait :anonymous_through_supporter do - supporter {build(:supporter_with_fv_poverty, nonprofit: nonprofit, anonymous: true) } - end + trait :anonymous_through_supporter do + supporter { build(:supporter_with_fv_poverty, nonprofit: nonprofit, anonymous: true) } + end end end diff --git a/spec/factories/payouts.rb b/spec/factories/payouts.rb index b1b07feda..4920713bd 100644 --- a/spec/factories/payouts.rb +++ b/spec/factories/payouts.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :payout do - stripe_transfer_id { 'tr_xxxxxxxxx' } + stripe_transfer_id { "tr_xxxxxxxxx" } email { Faker::Internet.email } net_amount { Faker::Number.number(digits: 5) } end diff --git a/spec/factories/profiles.rb b/spec/factories/profiles.rb index c56c9ab5e..f2b2c0bbd 100644 --- a/spec/factories/profiles.rb +++ b/spec/factories/profiles.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :profile do - sequence(:email) {|n|"eric#{n}@fjelkt.com"} + sequence(:email) { |n| "eric#{n}@fjelkt.com" } user end end diff --git a/spec/factories/reassignments.rb b/spec/factories/reassignments.rb index dc8d9ac70..3949a22c5 100644 --- a/spec/factories/reassignments.rb +++ b/spec/factories/reassignments.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :reassignment do - end end diff --git a/spec/factories/recurring_donation_holds.rb b/spec/factories/recurring_donation_holds.rb index 49afa2f28..2ed5b523e 100644 --- a/spec/factories/recurring_donation_holds.rb +++ b/spec/factories/recurring_donation_holds.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :recurring_donation_hold do - end end diff --git a/spec/factories/recurring_donations.rb b/spec/factories/recurring_donations.rb index a76228b50..319d75f2b 100644 --- a/spec/factories/recurring_donations.rb +++ b/spec/factories/recurring_donations.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :recurring_donation do - end - factory :recurring_donation_base, class: 'RecurringDonation' do - active {true} - sequence(:edit_token) {|i| "edit_token_#{i}"} + factory :recurring_donation_base, class: "RecurringDonation" do + active { true } + sequence(:edit_token) { |i| "edit_token_#{i}" } start_date { Time.current } interval { 1 } - time_unit { 'month' } + time_unit { "month" } end end diff --git a/spec/factories/refunds.rb b/spec/factories/refunds.rb index a2e7f8380..8d2124181 100644 --- a/spec/factories/refunds.rb +++ b/spec/factories/refunds.rb @@ -2,12 +2,11 @@ FactoryBot.define do factory :refund, aliases: [:refund_base] do trait :from_donation do - charge { build(:charge_base, payment: build(:payment, donation: build(:donation)))} + charge { build(:charge_base, payment: build(:payment, donation: build(:donation))) } end - trait :not_from_donation do - charge { build(:charge_base, payment: build(:payment))} + charge { build(:charge_base, payment: build(:payment)) } end end end diff --git a/spec/factories/roles.rb b/spec/factories/roles.rb index 3a5a175b1..5de5b081d 100644 --- a/spec/factories/roles.rb +++ b/spec/factories/roles.rb @@ -2,14 +2,13 @@ FactoryBot.define do factory :role, aliases: [:role_base] do trait :as_nonprofit_admin do - host {association :nonprofit_base} - name { 'nonprofit_admin'} + host { association :nonprofit_base } + name { "nonprofit_admin" } end trait :as_nonprofit_associate do - - host {association :nonprofit_base} - name { 'nonprofit_associate'} + host { association :nonprofit_base } + name { "nonprofit_associate" } end end end diff --git a/spec/factories/simple_objects.rb b/spec/factories/simple_objects.rb index 8cb6b9c40..545dbcf2e 100644 --- a/spec/factories/simple_objects.rb +++ b/spec/factories/simple_objects.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :simple_object do - factory :simple_object_with_nonprofit do - nonprofit {create(:nonprofit_base)} - + factory :simple_object_with_nonprofit do + nonprofit { create(:nonprofit_base) } + factory :simple_object_with_parent do - parent { create(:simple_object, parent: create(:simple_object), )} + parent { create(:simple_object, parent: create(:simple_object)) } factory :simple_object_with_friends_and_parent do - friends {[create(:simple_object), create(:simple_object, parent: create(:simple_object))]} + friends { [create(:simple_object), create(:simple_object, parent: create(:simple_object))] } end end end diff --git a/spec/factories/source_tokens.rb b/spec/factories/source_tokens.rb index d01550370..a8de2b49d 100644 --- a/spec/factories/source_tokens.rb +++ b/spec/factories/source_tokens.rb @@ -1,21 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :source_token do - - token {SecureRandom.uuid} + token { SecureRandom.uuid } max_uses { 1 } - expiration { Time.current + 10.minutes } + expiration { 10.minutes.from_now } factory :source_token_for_supporter_for_fv_poverty do tokenizable { build(:card, holder: create(:supporter_with_fv_poverty)) } end factory :source_token_base do - tokenizable { association :card_base} - trait :with_stripe_card do - tokenizable { association :card_base, :with_created_stripe_customer_and_card} + tokenizable { association :card_base } + trait :with_stripe_card do + tokenizable { association :card_base, :with_created_stripe_customer_and_card } end - - end end end diff --git a/spec/factories/stripe/stripe_accounts.rb b/spec/factories/stripe/stripe_accounts.rb index f62f0c099..c07ebaa24 100644 --- a/spec/factories/stripe/stripe_accounts.rb +++ b/spec/factories/stripe/stripe_accounts.rb @@ -3,4 +3,4 @@ factory :__stripe_account, aliases: [:stripe_account_base] do stripe_object_base end -end \ No newline at end of file +end diff --git a/spec/factories/stripe/stripe_cards.rb b/spec/factories/stripe/stripe_cards.rb index 4edb6d872..9f0614492 100644 --- a/spec/factories/stripe/stripe_cards.rb +++ b/spec/factories/stripe/stripe_cards.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do - factory :stripe_card, aliases: [:stripe_card_base], class: 'Stripe::Card' do + factory :stripe_card, aliases: [:stripe_card_base], class: "Stripe::Card" do stripe_object_base - + transient do - stripe_customer { association :stripe_customer_base } - stripe_token { association :stripe_token_base} - stripe_token_id { stripe_token.id} - stripe_customer_id { stripe_customer.id} - currency {'usd'} + stripe_customer { association :stripe_customer_base } + stripe_token { association :stripe_token_base } + stripe_token_id { stripe_token.id } + stripe_customer_id { stripe_customer.id } + currency { "usd" } end - + to_create do |instance, evaluator| source = Stripe::Customer.create_source(evaluator.stripe_customer_id, {source: evaluator.stripe_token_id}) instance.update_attributes(source) diff --git a/spec/factories/stripe/stripe_customers.rb b/spec/factories/stripe/stripe_customers.rb index cdbc490a1..cd22a83e1 100644 --- a/spec/factories/stripe/stripe_customers.rb +++ b/spec/factories/stripe/stripe_customers.rb @@ -1,7 +1,5 @@ FactoryBot.define do - factory :stripe_customer, aliases: [:stripe_customer_base], class: 'Stripe::Customer' do + factory :stripe_customer, aliases: [:stripe_customer_base], class: "Stripe::Customer" do stripe_object_base end - - -end \ No newline at end of file +end diff --git a/spec/factories/stripe/stripe_object_base.rb b/spec/factories/stripe/stripe_object_base.rb index 80641a8cc..117ef01e2 100644 --- a/spec/factories/stripe/stripe_object_base.rb +++ b/spec/factories/stripe/stripe_object_base.rb @@ -11,4 +11,3 @@ end end end - diff --git a/spec/factories/stripe/stripe_plans.rb b/spec/factories/stripe/stripe_plans.rb index 50f43958a..1aeac64ac 100644 --- a/spec/factories/stripe/stripe_plans.rb +++ b/spec/factories/stripe/stripe_plans.rb @@ -1,14 +1,12 @@ - FactoryBot.define do - factory :stripe_plan, aliases: [:stripe_plan_base], class: 'Stripe::Plan' do - + factory :stripe_plan, aliases: [:stripe_plan_base], class: "Stripe::Plan" do stripe_object_base - transient do - sequence(:id) {|i| "test_str_plan#{i}"} + transient do + sequence(:id) { |i| "test_str_plan#{i}" } product { association :stripe_product } end - currency {'usd'} + currency { "usd" } amount { 0 } to_create do |instance, evaluator| @@ -16,4 +14,4 @@ instance.update_attributes(plan) end end -end \ No newline at end of file +end diff --git a/spec/factories/stripe/stripe_product.rb b/spec/factories/stripe/stripe_product.rb index 52d9c7ea3..5a3c9ecbd 100644 --- a/spec/factories/stripe/stripe_product.rb +++ b/spec/factories/stripe/stripe_product.rb @@ -1,11 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do - factory :stripe_product, aliases: [:stripe_product_base], class: 'Stripe::Product' do - + factory :stripe_product, aliases: [:stripe_product_base], class: "Stripe::Product" do stripe_object_base - transient do - sequence(:id) {|i| "test_str_product#{i}"} + transient do + sequence(:id) { |i| "test_str_product#{i}" } end name { id } @@ -14,4 +13,4 @@ instance.update_attributes(product) end end -end \ No newline at end of file +end diff --git a/spec/factories/stripe/stripe_subscriptions.rb b/spec/factories/stripe/stripe_subscriptions.rb index 17e4cae74..860c8e46c 100644 --- a/spec/factories/stripe/stripe_subscriptions.rb +++ b/spec/factories/stripe/stripe_subscriptions.rb @@ -1,13 +1,12 @@ - FactoryBot.define do - factory :stripe_subscription, aliases: [:stripe_subscription_base], class: 'Stripe::Subscription' do + factory :stripe_subscription, aliases: [:stripe_subscription_base], class: "Stripe::Subscription" do stripe_object_base transient do - stripe_customer { association :stripe_customer_base} - stripe_plan {association :stripe_plan_base} + stripe_customer { association :stripe_customer_base } + stripe_plan { association :stripe_plan_base } end plan { stripe_plan.id } - customer { stripe_customer.id} + customer { stripe_customer.id } end -end \ No newline at end of file +end diff --git a/spec/factories/stripe/stripe_tokens.rb b/spec/factories/stripe/stripe_tokens.rb index 196c339c5..2bb4d490a 100644 --- a/spec/factories/stripe/stripe_tokens.rb +++ b/spec/factories/stripe/stripe_tokens.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do - factory :stripe_token, aliases: [:stripe_token_base], class: 'Stripe::Token' do - + factory :stripe_token, aliases: [:stripe_token_base], class: "Stripe::Token" do stripe_object_base to_create do |instance| @@ -9,4 +8,4 @@ instance.update_attributes(Stripe::Token.retrieve(new_token)) end end -end \ No newline at end of file +end diff --git a/spec/factories/stripe_accounts.rb b/spec/factories/stripe_accounts.rb index 47ddae2d5..0c13271c9 100644 --- a/spec/factories/stripe_accounts.rb +++ b/spec/factories/stripe_accounts.rb @@ -1,46 +1,46 @@ FactoryBot.define do factory :stripe_account do - stripe_account_id{ "test_acct_1"} - object {"{}"} + stripe_account_id { "test_acct_1" } + object { "{}" } - trait :with_pending do - object { StripeMockHelper.mock_webhook_event('account.updated.with-pending')['data']['object']} + trait :with_pending do + object { StripeMockHelper.mock_webhook_event("account.updated.with-pending")["data"]["object"] } end - trait :with_temporarily_verified do - object { StripeMockHelper.mock_webhook_event('account.updated.with-temporarily_verified')['data']['object']} + trait :with_temporarily_verified do + object { StripeMockHelper.mock_webhook_event("account.updated.with-temporarily_verified")["data"]["object"] } end - + trait :with_temporarily_verified_with_deadline do - object { StripeMockHelper.mock_webhook_event('account.updated.with-temporarily_verified-with-deadline')['data']['object']} + object { StripeMockHelper.mock_webhook_event("account.updated.with-temporarily_verified-with-deadline")["data"]["object"] } end trait :with_verified do - object { StripeMockHelper.mock_webhook_event('account.updated.with-verified')['data']['object']} + object { StripeMockHelper.mock_webhook_event("account.updated.with-verified")["data"]["object"] } end trait :with_verified_and_bank_provided_with_active_but_empty_future_requirements do - object { StripeMockHelper.mock_webhook_event('account.updated.with-verified-and-bank-provided-with-active-but-empty-future_requirements')['data']['object']} + object { StripeMockHelper.mock_webhook_event("account.updated.with-verified-and-bank-provided-with-active-but-empty-future_requirements")["data"]["object"] } end - trait :with_verified_and_bank_provided_but_future_requirements do - object { StripeMockHelper.mock_webhook_event('account.updated.with-verified-and-bank-provided-but-future-requirements')['data']['object']} + trait :with_verified_and_bank_provided_but_future_requirements do + object { StripeMockHelper.mock_webhook_event("account.updated.with-verified-and-bank-provided-but-future-requirements")["data"]["object"] } end - trait :with_verified_and_bank_provided_but_future_requirements_pending do - object { StripeMockHelper.mock_webhook_event('account.updated.with-verified-and-bank-provided-but-future-requirements-pending')['data']['object']} + trait :with_verified_and_bank_provided_but_future_requirements_pending do + object { StripeMockHelper.mock_webhook_event("account.updated.with-verified-and-bank-provided-but-future-requirements-pending")["data"]["object"] } end trait :with_unverified do - object { StripeMockHelper.mock_webhook_event('account.updated.with-unverified')['data']['object']} + object { StripeMockHelper.mock_webhook_event("account.updated.with-unverified")["data"]["object"] } end trait :with_unverified_from_verified do - object { StripeMockHelper.mock_webhook_event('account.updated.with-unverified-from-verified')['data']['object']} + object { StripeMockHelper.mock_webhook_event("account.updated.with-unverified-from-verified")["data"]["object"] } end trait :without_future_requirements do - object {StripeMockHelper.mock_webhook_event('account.updated.without-future-requirements')['data']['object']} + object { StripeMockHelper.mock_webhook_event("account.updated.without-future-requirements")["data"]["object"] } end end end diff --git a/spec/factories/stripe_disputes.rb b/spec/factories/stripe_disputes.rb index ed7fba29f..b0560ca6f 100644 --- a/spec/factories/stripe_disputes.rb +++ b/spec/factories/stripe_disputes.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :stripe_dispute do - stripe_dispute_id {"dp_05RsQX2eZvKYlo2C0FRTGSSA"} - stripe_charge_id {"ch_1Y7zzfBCJIIhvMWmSiNWrPAC"} + stripe_dispute_id { "dp_05RsQX2eZvKYlo2C0FRTGSSA" } + stripe_charge_id { "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" } end end diff --git a/spec/factories/stripe_transaction_charges.rb b/spec/factories/stripe_transaction_charges.rb index 6e54bd363..8588b3b9c 100644 --- a/spec/factories/stripe_transaction_charges.rb +++ b/spec/factories/stripe_transaction_charges.rb @@ -2,10 +2,10 @@ factory :stripe_transaction_charge do transient do gross_amount { 4000 } - fee_total { -300} - net_amount { gross_amount - fee_total} - supporter {create(:supporter_with_fv_poverty)} - nonprofit {supporter.nonprofit} + fee_total { -300 } + net_amount { gross_amount - fee_total } + supporter { create(:supporter_with_fv_poverty) } + nonprofit { supporter.nonprofit } end end end diff --git a/spec/factories/stripe_transaction_dispute_reversals.rb b/spec/factories/stripe_transaction_dispute_reversals.rb index 3c543a8ce..d2e989ffc 100644 --- a/spec/factories/stripe_transaction_dispute_reversals.rb +++ b/spec/factories/stripe_transaction_dispute_reversals.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :stripe_transaction_dispute_reversal do - end end diff --git a/spec/factories/stripe_transaction_disputes.rb b/spec/factories/stripe_transaction_disputes.rb index 0708dda07..52e065b72 100644 --- a/spec/factories/stripe_transaction_disputes.rb +++ b/spec/factories/stripe_transaction_disputes.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :stripe_transaction_dispute do - end end diff --git a/spec/factories/stripe_transaction_refunds.rb b/spec/factories/stripe_transaction_refunds.rb index f9a1407f4..1ef2a69ae 100644 --- a/spec/factories/stripe_transaction_refunds.rb +++ b/spec/factories/stripe_transaction_refunds.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :stripe_transaction_refund do - end end diff --git a/spec/factories/stripe_transactions.rb b/spec/factories/stripe_transactions.rb index 07f40be6d..c7edae651 100644 --- a/spec/factories/stripe_transactions.rb +++ b/spec/factories/stripe_transactions.rb @@ -3,18 +3,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE FactoryBot.define do - factory :stripe_transaction do - amount { 4000 } - factory :stripe_transaction_for_testing_payment_extensions do - transient do - currency {'fake'} - end - - amount {707} - - subtransaction{build(:subtransaction_for_testing_payment_extensions)} - end - end + factory :stripe_transaction do + amount { 4000 } + factory :stripe_transaction_for_testing_payment_extensions do + transient do + currency { "fake" } + end - + amount { 707 } + + subtransaction { build(:subtransaction_for_testing_payment_extensions) } + end + end end diff --git a/spec/factories/subtransaction_payments.rb b/spec/factories/subtransaction_payments.rb index ebaf88b50..1e120c4aa 100644 --- a/spec/factories/subtransaction_payments.rb +++ b/spec/factories/subtransaction_payments.rb @@ -3,94 +3,86 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE FactoryBot.define do - factory :subtransaction_payment do - transient do - gross_amount { 4000} - - fee_total { -300} - net_amount { gross_amount + fee_total} - end - legacy_payment { build(:payment, gross_amount: gross_amount, net_amount: net_amount, fee_total: fee_total, date: Time.current) } - paymentable { create(:offline_transaction_charge) } + factory :subtransaction_payment do + transient do + gross_amount { 4000 } - factory :subtransaction_payment_with_offline_charge do - - paymentable { create(:offline_transaction_charge) } - payment { build(:payment, gross_amount: gross_amount, net_amount: net_amount, fee_total: fee_total, date: Time.current) } - end + fee_total { -300 } + net_amount { gross_amount + fee_total } + end + legacy_payment { build(:payment, gross_amount: gross_amount, net_amount: net_amount, fee_total: fee_total, date: Time.current) } + paymentable { create(:offline_transaction_charge) } - factory :subtransaction_payment_for_refund_initial_charge do - transient do - nonprofit {supporter.nonprofit} - supporter { create(:supporter_with_fv_poverty)} - gross_amount { 4000} - fee_total { -300} - net_amount {gross_amount+ fee_total} - end + factory :subtransaction_payment_with_offline_charge do + paymentable { create(:offline_transaction_charge) } + payment { build(:payment, gross_amount: gross_amount, net_amount: net_amount, fee_total: fee_total, date: Time.current) } + end - paymentable { - build( - :stripe_transaction_charge, + factory :subtransaction_payment_for_refund_initial_charge do + transient do + nonprofit { supporter.nonprofit } + supporter { create(:supporter_with_fv_poverty) } + gross_amount { 4000 } + fee_total { -300 } + net_amount { gross_amount + fee_total } + end - gross_amount: gross_amount, - fee_total: fee_total, - nonprofit:nonprofit, - supporter:supporter) - } + paymentable { + build( + :stripe_transaction_charge, + gross_amount: gross_amount, + fee_total: fee_total, + nonprofit: nonprofit, + supporter: supporter + ) + } - legacy_payment { - build(:payment, - gross_amount: gross_amount, - fee_total: fee_total, - net_amount: net_amount, - nonprofit: nonprofit, - supporter: supporter, - date: Time.current, - charge: build(:charge, - nonprofit: nonprofit, - supporter: supporter, - created_at: Time.current, - amount: gross_amount, - fee: fee_total - ) - ) - } + legacy_payment { + build(:payment, + gross_amount: gross_amount, + fee_total: fee_total, + net_amount: net_amount, + nonprofit: nonprofit, + supporter: supporter, + date: Time.current, + charge: build(:charge, + nonprofit: nonprofit, + supporter: supporter, + created_at: Time.current, + amount: gross_amount, + fee: fee_total)) + } + end - end + factory :subtransaction_payment_for_offline_transaction_charge do + transient do + nonprofit { supporter.nonprofit } + supporter { create(:supporter_with_fv_poverty) } + gross_amount { 4000 } + fee_total { 0 } + net_amount { gross_amount + fee_total } + end - factory :subtransaction_payment_for_offline_transaction_charge do - transient do - nonprofit {supporter.nonprofit} - supporter { create(:supporter_with_fv_poverty)} - gross_amount { 4000} - fee_total { 0} - net_amount {gross_amount+ fee_total} - end + paymentable { + build( + :offline_transaction_charge + ) + } - paymentable { - build( - :offline_transaction_charge) - } - - legacy_payment { - build(:payment, - gross_amount: gross_amount, - fee_total: fee_total, - net_amount: net_amount, - nonprofit: nonprofit, - supporter: supporter, - date: Time.current, - ) - } - - end - end - - - factory :subtransaction_payment_base, class: 'SubtransactionPayment' do - - legacy_payment { nil } - paymentable { build(:offline_transaction_charge_base)} - end + legacy_payment { + build(:payment, + gross_amount: gross_amount, + fee_total: fee_total, + net_amount: net_amount, + nonprofit: nonprofit, + supporter: supporter, + date: Time.current) + } + end + end + factory :subtransaction_payment_base, class: "SubtransactionPayment" do + legacy_payment { nil } + paymentable { build(:offline_transaction_charge_base) } + end end diff --git a/spec/factories/subtransactions.rb b/spec/factories/subtransactions.rb index 17708dd18..bc2eccbff 100644 --- a/spec/factories/subtransactions.rb +++ b/spec/factories/subtransactions.rb @@ -3,107 +3,109 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE FactoryBot.define do - factory :subtransaction do - - subtransactable { create(:offline_transaction) } - subtransaction_payments do - [ - build(:subtransaction_payment_with_offline_charge) - ] - end + factory :subtransaction do + subtransactable { create(:offline_transaction) } + subtransaction_payments do + [ + build(:subtransaction_payment_with_offline_charge) + ] + end - factory :subtransaction_for_testing_payment_extensions do - transient do - currency {'fake'} - end + factory :subtransaction_for_testing_payment_extensions do + transient do + currency { "fake" } + end - trx {build(:transaction, nonprofit: build(:fv_poverty, currency: currency))} - subtransaction_payments {[ - build(:subtransaction_payment, - gross_amount: 101, - fee_total: -1), - build(:subtransaction_payment, - gross_amount: 202, - fee_total: -2), - build(:subtransaction_payment, - gross_amount: 404, - fee_total: -4) - ] } - end + trx { build(:transaction, nonprofit: build(:fv_poverty, currency: currency)) } + subtransaction_payments { + [ + build(:subtransaction_payment, + gross_amount: 101, + fee_total: -1), + build(:subtransaction_payment, + gross_amount: 202, + fee_total: -2), + build(:subtransaction_payment, + gross_amount: 404, + fee_total: -4) + ] + } + end - factory :subtransaction_for_offline_donation, class: "Subtransaction" do - transient do - nonprofit {supporter.nonprofit} - supporter { create(:supporter_with_fv_poverty)} - gross_amount { 4000} - fee_total { 0} - net_amount {gross_amount+ fee_total} - end - subtransactable { - build(:offline_transaction, amount: gross_amount) - - } - - subtransaction_payments {[ - build(:subtransaction_payment_for_offline_transaction_charge, - subtransaction: @instance, - gross_amount: gross_amount, - fee_total: fee_total, - nonprofit:nonprofit, - supporter:supporter) - - ]} - end + factory :subtransaction_for_offline_donation, class: "Subtransaction" do + transient do + nonprofit { supporter.nonprofit } + supporter { create(:supporter_with_fv_poverty) } + gross_amount { 4000 } + fee_total { 0 } + net_amount { gross_amount + fee_total } + end + subtransactable { + build(:offline_transaction, amount: gross_amount) + } - factory :subtransaction_for_refund, class: "Subtransaction" do - transient do - nonprofit {supporter.nonprofit} - supporter { build(:subtransaction_payment_for_offline_transaction_charge)} - # initial_payment { - # build(:subtransaction_payment, paymentable: - # build( - # :stripe_transaction_charge, - - # gross_amount: gross_amount, - # fee_total: fee_total, - # nonprofit:nonprofit, - # supporter:supporter) - # ) - - # } - - gross_amount { 4000} - fee_total { -300} - net_amount {gross_amount+ fee_total} - end - subtransactable { - build(:stripe_transaction, amount: gross_amount) - - } - - subtransaction_payments {[ - association(:subtransaction_payment_for_refund_initial_charge, - subtransaction: @instance, - gross_amount: gross_amount, - fee_total: fee_total, - nonprofit:nonprofit, - supporter:supporter) - - ]} - end - end + subtransaction_payments { + [ + build(:subtransaction_payment_for_offline_transaction_charge, + subtransaction: @instance, + gross_amount: gross_amount, + fee_total: fee_total, + nonprofit: nonprofit, + supporter: supporter) - factory :subtransaction_base, class: 'Subtransaction' do - transient do - legacy_payments {nil} - end - subtransactable {build :offline_transaction_base} - after(:build) do |instance, evaluator| - legacy_payments = evaluator.legacy_payments.is_a?(Payment) ? [evaluator.legacy_payments] : evaluator.legacy_payments - legacy_payments.each do |legacy_payment| - instance.subtransaction_payments << build(:subtransaction_payment_base, legacy_payment: legacy_payment) - end - end - end + ] + } + end + factory :subtransaction_for_refund, class: "Subtransaction" do + transient do + nonprofit { supporter.nonprofit } + supporter { build(:subtransaction_payment_for_offline_transaction_charge) } + # initial_payment { + # build(:subtransaction_payment, paymentable: + # build( + # :stripe_transaction_charge, + + # gross_amount: gross_amount, + # fee_total: fee_total, + # nonprofit:nonprofit, + # supporter:supporter) + # ) + + # } + + gross_amount { 4000 } + fee_total { -300 } + net_amount { gross_amount + fee_total } + end + subtransactable { + build(:stripe_transaction, amount: gross_amount) + } + + subtransaction_payments { + [ + association(:subtransaction_payment_for_refund_initial_charge, + subtransaction: @instance, + gross_amount: gross_amount, + fee_total: fee_total, + nonprofit: nonprofit, + supporter: supporter) + + ] + } + end + end + + factory :subtransaction_base, class: "Subtransaction" do + transient do + legacy_payments { nil } + end + subtransactable { build :offline_transaction_base } + after(:build) do |instance, evaluator| + legacy_payments = evaluator.legacy_payments.is_a?(Payment) ? [evaluator.legacy_payments] : evaluator.legacy_payments + legacy_payments.each do |legacy_payment| + instance.subtransaction_payments << build(:subtransaction_payment_base, legacy_payment: legacy_payment) + end + end + end end diff --git a/spec/factories/supporter_addresses.rb b/spec/factories/supporter_addresses.rb index 0aa6ee552..66b70dbcd 100644 --- a/spec/factories/supporter_addresses.rb +++ b/spec/factories/supporter_addresses.rb @@ -1,30 +1,30 @@ FactoryBot.define do factory :supporter_address do - address {"MyString"} + address { "MyString" } supporter end trait :with_empty_address do address { nil } - city { nil} + city { nil } state_code { nil } - zip_code { nil} - country {nil} + zip_code { nil } + country { nil } end trait :with_blank_address do - address { '' } - city { ''} - state_code { '' } - zip_code { ''} - country {''} + address { "" } + city { "" } + state_code { "" } + zip_code { "" } + country { "" } end # we may need this is a set of places, like orders so let's just keep it here trait :with_custom_address_1 do - address { '123 Address 1 Street' } - city {'Appleton'} + address { "123 Address 1 Street" } + city { "Appleton" } state_code { "WI" } - zip_code {'54915'} - country {'United States'} + zip_code { "54915" } + country { "United States" } end end diff --git a/spec/factories/supporter_notes.rb b/spec/factories/supporter_notes.rb index 80c264cff..18c90cd35 100644 --- a/spec/factories/supporter_notes.rb +++ b/spec/factories/supporter_notes.rb @@ -1,5 +1,4 @@ FactoryBot.define do factory :supporter_note do - end end diff --git a/spec/factories/supporters.rb b/spec/factories/supporters.rb index 2f0ed3a1c..4aa57237a 100644 --- a/spec/factories/supporters.rb +++ b/spec/factories/supporters.rb @@ -1,19 +1,19 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :supporter do - name {"Fake Supporter Name"} + name { "Fake Supporter Name" } nonprofit trait :has_a_card do - after(:create) {|supporter| + after(:create) { |supporter| create(:active_card_1, holder: supporter) } end end - factory :supporter_generator, class: 'Supporter' do + factory :supporter_generator, class: "Supporter" do sequence(:id) - + name { Faker::Name.name } email { Faker::Internet.email } nonprofit @@ -24,20 +24,18 @@ end trait :with_primary_address do - addresses { [build(:supporter_address)]} - primary_address { addresses.first} + addresses { [build(:supporter_address)] } + primary_address { addresses.first } end - factory :supporter_with_fv_poverty, aliases: [:supporter_base], class: 'Supporter' do - name { 'Fake Supporter Name' } - nonprofit { association :nonprofit_base, vetted: true} + factory :supporter_with_fv_poverty, aliases: [:supporter_base], class: "Supporter" do + name { "Fake Supporter Name" } + nonprofit { association :nonprofit_base, vetted: true } trait :with_1_active_mailing_list do - nonprofit { association :nonprofit_base, :with_active_mailing_list} + nonprofit { association :nonprofit_base, :with_active_mailing_list } after(:create) do |supporter| supporter.tag_joins.create(tag_master: supporter.nonprofit.tag_masters.where("NOT deleted").first) end end end - - end diff --git a/spec/factories/tag_joins.rb b/spec/factories/tag_joins.rb index abda3b505..704b105b9 100644 --- a/spec/factories/tag_joins.rb +++ b/spec/factories/tag_joins.rb @@ -1,13 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :tag_join do - tag_master_id {1} - supporter_id {4} - created_at {DateTime.now} - updated_at {DateTime.now} + tag_master_id { 1 } + supporter_id { 4 } + created_at { DateTime.now } + updated_at { DateTime.now } end - factory :tag_join_base, class: 'TagJoin' do - tag_master { association :tag_master_base} + factory :tag_join_base, class: "TagJoin" do + tag_master { association :tag_master_base } end end diff --git a/spec/factories/tag_masters.rb b/spec/factories/tag_masters.rb index f9d650d28..76501433a 100644 --- a/spec/factories/tag_masters.rb +++ b/spec/factories/tag_masters.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :tag_master do - end factory :tag_master_base, class: "TagMaster" do - sequence(:name) {|i| "tag_name_#{i}"} + sequence(:name) { |i| "tag_name_#{i}" } deleted { false } trait :with_email_list do - email_list { build(:email_list_base, nonprofit: nonprofit)} + email_list { build(:email_list_base, nonprofit: nonprofit) } end end end diff --git a/spec/factories/ticket_levels.rb b/spec/factories/ticket_levels.rb index 4b3751c61..6727564db 100644 --- a/spec/factories/ticket_levels.rb +++ b/spec/factories/ticket_levels.rb @@ -2,7 +2,6 @@ FactoryBot.define do factory :ticket_level do trait :has_tickets do - end end end diff --git a/spec/factories/ticket_purchases.rb b/spec/factories/ticket_purchases.rb index eab63b14e..81e97c220 100644 --- a/spec/factories/ticket_purchases.rb +++ b/spec/factories/ticket_purchases.rb @@ -5,6 +5,5 @@ FactoryBot.define do factory :ticket_purchase do - end end diff --git a/spec/factories/tickets.rb b/spec/factories/tickets.rb index 8da21c3a4..99e045e11 100644 --- a/spec/factories/tickets.rb +++ b/spec/factories/tickets.rb @@ -1,7 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :ticket do - trait :has_event do event end diff --git a/spec/factories/transaction_assignments.rb b/spec/factories/transaction_assignments.rb index 76a2c06f8..31097aeed 100644 --- a/spec/factories/transaction_assignments.rb +++ b/spec/factories/transaction_assignments.rb @@ -9,11 +9,10 @@ factory :transaction_assignment_base, class: "TransactionAssignment" do transient do - legacy_donation { nil} + legacy_donation { nil } end after(:build) do |instance, evaluator| - instance.assignable = build(:modern_donation_base, legacy_donation:evaluator.legacy_donation) + instance.assignable = build(:modern_donation_base, legacy_donation: evaluator.legacy_donation) end end - end diff --git a/spec/factories/transactions.rb b/spec/factories/transactions.rb index d4286483c..0409b4cf1 100644 --- a/spec/factories/transactions.rb +++ b/spec/factories/transactions.rb @@ -3,142 +3,138 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE FactoryBot.define do - factory :transaction do - supporter { create(:supporter) } - end - - - factory :transaction_base, class: "Transaction" do - transient do - legacy_donation { nil} - legacy_payments { legacy_donation.payments.first} - end - supporter { association :supporter_base} - after(:build) do |instance, evaluator| - instance.transaction_assignments << build(:transaction_assignment_base, legacy_donation: evaluator.legacy_donation) - instance.subtransaction = build(:subtransaction_base,legacy_payments: evaluator.legacy_payments) - end - - factory :transaction_with_legacy_donation do - supporter { create(:supporter_with_fv_poverty) } - - legacy_donation { build(:donation, - supporter: supporter, - amount: 4000, - nonprofit:supporter.nonprofit, - designation: 'Designation 1', - payments: [build(:payment_base, gross_amount: 4000, supporter: supporter, nonprofit: supporter.nonprofit)], - )} - end - - factory :transaction_for_testing_payment_extensions do - supporter { create(:supporter_with_fv_poverty, nonprofit:nonprofit) } - - transient do - nonprofit { build(:fv_poverty, currency: currency)} - currency {'fake'} - legacy_donation { build(:donation, - supporter: supporter, - amount: 4000, - nonprofit:supporter.nonprofit, - designation: 'Designation 1', - payments: [ - build(:payment_base, supporter: supporter, nonprofit: supporter.nonprofit, gross_amount: 101, fee_total: -1), - build(:payment_base, supporter: supporter, nonprofit: supporter.nonprofit, gross_amount: 202, fee_total: -2), - build(:payment_base, supporter: supporter, nonprofit: supporter.nonprofit, gross_amount: 404, fee_total: -4) - ] - )} - legacy_payments { - legacy_donation.payments - } - end - end - end - - factory :transaction_for_offline_donation, class: "Transaction" do - transient do - - offline_transaction_charge { subtransaction.subtransaction_payments.first} - payment { - offline_transaction_charge&.legacy_payment - } - gross_amount { 4000 } - fee_total { 0} - nonprofit { supporter.nonprofit} - - end - - amount { gross_amount } - - supporter { create(:supporter_with_fv_poverty) } - subtransaction { build(:subtransaction_for_offline_donation, - supporter: supporter, - gross_amount: gross_amount, - fee_total: fee_total) - } - - transaction_assignments { - ta = [ - build(:transaction_assignment, - assignable: - build(:modern_donation, - legacy_donation: - build(:donation, - supporter: supporter, - amount: gross_amount, - nonprofit:nonprofit, - designation: 'Designation 1', - payment: payment, - ) - ) - ) - ] - - ta - } - end - - factory :transaction_for_refund, class: "Transaction" do - transient do - - stripe_transaction_charge { subtransaction.subtransaction_payments.first} - payment { - stripe_transaction_charge&.legacy_payment - } - gross_amount { 4000 } - fee_total { -300} - nonprofit { supporter.nonprofit} - - end - - supporter { create(:supporter_with_fv_poverty) } - subtransaction { association :subtransaction_for_refund, - gross_amount: gross_amount, - fee_total: fee_total, - supporter: supporter - } - end - - # factory :transaction_for_testing_payment_extensions, class: "Transaction" do - # transient do - # currency {'fake'} - # payments {[ - # build(:subtransaction_payment, - # gross_amount: 101, - # fee_total: -1), - # build(:subtransaction_payment, - # gross_amount: 202, - # fee_total: -2), - # build(:subtransaction_payment, - # gross_amount: 404, - # fee_total: -4) - # ] } - # end - # amount { 707 } - # nonprofit { build(:nonprofit, currency: currency)} - # subtransaction { - # build(:subtransaction, subtransaction_payments: payments) - # } - - # end + factory :transaction do + supporter { create(:supporter) } + end + + factory :transaction_base, class: "Transaction" do + transient do + legacy_donation { nil } + legacy_payments { legacy_donation.payments.first } + end + supporter { association :supporter_base } + after(:build) do |instance, evaluator| + instance.transaction_assignments << build(:transaction_assignment_base, legacy_donation: evaluator.legacy_donation) + instance.subtransaction = build(:subtransaction_base, legacy_payments: evaluator.legacy_payments) + end + + factory :transaction_with_legacy_donation do + supporter { create(:supporter_with_fv_poverty) } + + legacy_donation { + build(:donation, + supporter: supporter, + amount: 4000, + nonprofit: supporter.nonprofit, + designation: "Designation 1", + payments: [build(:payment_base, gross_amount: 4000, supporter: supporter, nonprofit: supporter.nonprofit)]) + } + end + + factory :transaction_for_testing_payment_extensions do + supporter { create(:supporter_with_fv_poverty, nonprofit: nonprofit) } + + transient do + nonprofit { build(:fv_poverty, currency: currency) } + currency { "fake" } + legacy_donation { + build(:donation, + supporter: supporter, + amount: 4000, + nonprofit: supporter.nonprofit, + designation: "Designation 1", + payments: [ + build(:payment_base, supporter: supporter, nonprofit: supporter.nonprofit, gross_amount: 101, fee_total: -1), + build(:payment_base, supporter: supporter, nonprofit: supporter.nonprofit, gross_amount: 202, fee_total: -2), + build(:payment_base, supporter: supporter, nonprofit: supporter.nonprofit, gross_amount: 404, fee_total: -4) + ]) + } + legacy_payments { + legacy_donation.payments + } + end + end + end + + factory :transaction_for_offline_donation, class: "Transaction" do + transient do + offline_transaction_charge { subtransaction.subtransaction_payments.first } + payment { + offline_transaction_charge&.legacy_payment + } + gross_amount { 4000 } + fee_total { 0 } + nonprofit { supporter.nonprofit } + end + + amount { gross_amount } + + supporter { create(:supporter_with_fv_poverty) } + subtransaction { + build(:subtransaction_for_offline_donation, + supporter: supporter, + gross_amount: gross_amount, + fee_total: fee_total) + } + + transaction_assignments { + ta = [ + build(:transaction_assignment, + assignable: + build(:modern_donation, + legacy_donation: + build(:donation, + supporter: supporter, + amount: gross_amount, + nonprofit: nonprofit, + designation: "Designation 1", + payment: payment))) + ] + + ta + } + end + + factory :transaction_for_refund, class: "Transaction" do + transient do + stripe_transaction_charge { subtransaction.subtransaction_payments.first } + payment { + stripe_transaction_charge&.legacy_payment + } + gross_amount { 4000 } + fee_total { -300 } + nonprofit { supporter.nonprofit } + end + + supporter { create(:supporter_with_fv_poverty) } + subtransaction { + association :subtransaction_for_refund, + gross_amount: gross_amount, + fee_total: fee_total, + supporter: supporter + } + end + + # factory :transaction_for_testing_payment_extensions, class: "Transaction" do + # transient do + # currency {'fake'} + # payments {[ + # build(:subtransaction_payment, + # gross_amount: 101, + # fee_total: -1), + # build(:subtransaction_payment, + # gross_amount: 202, + # fee_total: -2), + # build(:subtransaction_payment, + # gross_amount: 404, + # fee_total: -4) + # ] } + # end + # amount { 707 } + # nonprofit { build(:nonprofit, currency: currency)} + # subtransaction { + # build(:subtransaction, subtransaction_payments: payments) + # } + + # end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 32a7b289e..46f64b79b 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later FactoryBot.define do factory :user, aliases: [:user_base] do - sequence(:email) {|i| "user#{i}@example.string.com"} - password {"whocares"} + sequence(:email) { |i| "user#{i}@example.string.com" } + password { "whocares" } trait :confirmed do - confirmed_at { Time.current - 1.day} + confirmed_at { 1.day.ago } end end - factory :automated_user, class: User do - email { "automated_user@automated_user.user"} - password {"whocares"} + factory :automated_user, class: User do + email { "automated_user@automated_user.user" } + password { "whocares" } id { 540 } end @@ -19,11 +19,13 @@ nonprofit { create(:nonprofit_base) } end - sequence(:email) {|i| "user_nonprofit_admin#{i}@example.string.com"} - password {"whocares"} - roles {[ - build(:role, name: 'nonprofit_admin', host: nonprofit) - ]} + sequence(:email) { |i| "user_nonprofit_admin#{i}@example.string.com" } + password { "whocares" } + roles { + [ + build(:role, name: "nonprofit_admin", host: nonprofit) + ] + } end factory :user_as_nonprofit_associate, class: User do @@ -31,11 +33,13 @@ nonprofit { create(:nonprofit_base) } end - sequence(:email) {|i| "user_nonprofit_associate#{i}@example.string.com"} - password {"whocares"} - roles {[ - build(:role, name: 'nonprofit_associate', host: nonprofit) - ]} + sequence(:email) { |i| "user_nonprofit_associate#{i}@example.string.com" } + password { "whocares" } + roles { + [ + build(:role, name: "nonprofit_associate", host: nonprofit) + ] + } trait :with_first_name do name { Faker::Name.first_name } @@ -46,11 +50,13 @@ transient do nonprofit { create(:nonprofit_base) } end - sequence(:email) {|i| "user#{i}@example.string.com"} - password {"whocares"} - roles {[ - build(:role, name: 'nonprofit_associate', host: create(:nonprofit_base)), - build(:role, name: 'super_admin') - ]} + sequence(:email) { |i| "user#{i}@example.string.com" } + password { "whocares" } + roles { + [ + build(:role, name: "nonprofit_associate", host: create(:nonprofit_base)), + build(:role, name: "super_admin") + ] + } end end diff --git a/spec/factory_specs/cards_spec.rb b/spec/factory_specs/cards_spec.rb index 77a9d4fea..d64f59579 100644 --- a/spec/factory_specs/cards_spec.rb +++ b/spec/factory_specs/cards_spec.rb @@ -1,19 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -describe 'cards factory' do +describe "cards factory" do describe :cards_base do context :with_created_stripe_customer_and_card do it { card = create(:card_base, :with_created_stripe_customer_and_card) expect(card.stripe_card).to_not be_nil - } it { card = create(:card_base, :with_created_stripe_customer_and_card) expect(card.stripe_customer).to_not be_nil - } end end -end \ No newline at end of file +end diff --git a/spec/factory_specs/json_expectations/transactions_spec.rb b/spec/factory_specs/json_expectations/transactions_spec.rb index 7415395bd..f49f8f727 100644 --- a/spec/factory_specs/json_expectations/transactions_spec.rb +++ b/spec/factory_specs/json_expectations/transactions_spec.rb @@ -1,10 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -describe 'trx factory' do +describe "trx factory" do it { expect(build(:trx, :concrete).to_h).to match(build(:trx).to_h) } - - end - \ No newline at end of file diff --git a/spec/factory_specs/nonprofits_spec.rb b/spec/factory_specs/nonprofits_spec.rb index 86e068b06..edaf17c32 100644 --- a/spec/factory_specs/nonprofits_spec.rb +++ b/spec/factory_specs/nonprofits_spec.rb @@ -1,27 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -describe 'nonprofits factory' do - +describe "nonprofits factory" do describe :with_billing_subscription_on_stripe do - - it 'creates one Nonprofit' do + it "creates one Nonprofit" do create(:nonprofit_base, :with_billing_subscription_on_stripe) expect(Nonprofit.count).to eq 1 end - it 'creates one BillingSubscription' do + it "creates one BillingSubscription" do create(:nonprofit_base, :with_billing_subscription_on_stripe) expect(BillingSubscription.count).to eq 1 end - - it 'creates 1 BillingPlan' do + + it "creates 1 BillingPlan" do create(:nonprofit_base, :with_billing_subscription_on_stripe) expect(BillingPlan.count).to eq 1 end - it 'creates 1 Card' do + it "creates 1 Card" do create(:nonprofit_base, :with_billing_subscription_on_stripe) expect(Card.count).to eq 1 end end -end \ No newline at end of file +end diff --git a/spec/factory_specs/nonprofits_specs.rb b/spec/factory_specs/nonprofits_specs.rb index 9c88a7ba2..fb99066b0 100644 --- a/spec/factory_specs/nonprofits_specs.rb +++ b/spec/factory_specs/nonprofits_specs.rb @@ -1,12 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -describe 'nonprofits factory' do - +describe "nonprofits factory" do describe :with_billing_subscription_on_stripe do - it { nonprofit = create(:nonprofit_base, :with_billing_subscription_on_stripe) expect(nonprofit).to have_attributes(attributes_for(:nonprofit_base, :with_billing_subscription_on_stripe)) } end -end \ No newline at end of file +end diff --git a/spec/factory_specs/source_tokens_spec.rb b/spec/factory_specs/source_tokens_spec.rb index 2e8e16bc5..c34d788ce 100644 --- a/spec/factory_specs/source_tokens_spec.rb +++ b/spec/factory_specs/source_tokens_spec.rb @@ -1,17 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -describe 'nonprofits factory' do - +describe "nonprofits factory" do describe :source_token_base do def create_stb create(:source_token_base, :with_stripe_card) end - it 'is associated with a card record' do - source = create_stb - expect(source.tokenizable.stripe_card).to be_a Stripe::Card + it "is associated with a card record" do + source = create_stb + expect(source.tokenizable.stripe_card).to be_a Stripe::Card end - - end -end \ No newline at end of file +end diff --git a/spec/factory_specs/stripe/stripe_cards_spec.rb b/spec/factory_specs/stripe/stripe_cards_spec.rb index d18f14b3b..41db2e98a 100644 --- a/spec/factory_specs/stripe/stripe_cards_spec.rb +++ b/spec/factory_specs/stripe/stripe_cards_spec.rb @@ -1,20 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" describe :stripe_card do - it 'provides a Stripe::Card' do + it "provides a Stripe::Card" do card = create(:stripe_card_base) expect(card).to be_a Stripe::Card end - it 'can be retrieved if requested' do + it "can be retrieved if requested" do card = create(:stripe_card_base) server_card = Stripe::Customer.retrieve_source(card.customer, card.id) expect(card).to eq server_card end - it 'creates 1 Stripe::Customer' do + it "creates 1 Stripe::Customer" do create(:stripe_card_base) expect(StripeMockHelper.instance.customers.count).to eq 1 end -end \ No newline at end of file +end diff --git a/spec/factory_specs/stripe/stripe_customers_spec.rb b/spec/factory_specs/stripe/stripe_customers_spec.rb index 68c64c56e..a033904d0 100644 --- a/spec/factory_specs/stripe/stripe_customers_spec.rb +++ b/spec/factory_specs/stripe/stripe_customers_spec.rb @@ -1,16 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" describe :stripe_customer do - it 'provides a Stripe::Customer' do + it "provides a Stripe::Customer" do customer = create(:stripe_customer_base) expect(customer).to be_a Stripe::Customer end - it 'can be retrieved if requested' do + it "can be retrieved if requested" do customer = create(:stripe_customer_base) server_customer = Stripe::Customer.retrieve(customer.id) expect(customer).to eq server_customer end - - -end \ No newline at end of file +end diff --git a/spec/factory_specs/stripe/stripe_plans_spec.rb b/spec/factory_specs/stripe/stripe_plans_spec.rb index 643d3ffb5..b303fd7cf 100644 --- a/spec/factory_specs/stripe/stripe_plans_spec.rb +++ b/spec/factory_specs/stripe/stripe_plans_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" describe :stripe_plan do - it 'provides a Stripe::Plan' do + it "provides a Stripe::Plan" do plan = create(:stripe_plan) expect(plan).to be_a Stripe::Plan end - it 'can be retrieved if requested' do + it "can be retrieved if requested" do plan = create(:stripe_plan) server_plan = Stripe::Plan.retrieve(plan.id) expect(plan).to eq server_plan end -end \ No newline at end of file +end diff --git a/spec/factory_specs/stripe/stripe_products_spec.rb b/spec/factory_specs/stripe/stripe_products_spec.rb index e9cb32a53..5f9746049 100644 --- a/spec/factory_specs/stripe/stripe_products_spec.rb +++ b/spec/factory_specs/stripe/stripe_products_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" describe :stripe_product do - it 'provides a Stripe::Product' do + it "provides a Stripe::Product" do product = create(:stripe_product) expect(product).to be_a Stripe::Product end - it 'can be retrieved if requested' do + it "can be retrieved if requested" do product = create(:stripe_product) server_product = Stripe::Product.retrieve(product.id) expect(product).to eq server_product end -end \ No newline at end of file +end diff --git a/spec/factory_specs/stripe/stripe_subscriptions_spec.rb b/spec/factory_specs/stripe/stripe_subscriptions_spec.rb index e10a3655b..d1a1493b3 100644 --- a/spec/factory_specs/stripe/stripe_subscriptions_spec.rb +++ b/spec/factory_specs/stripe/stripe_subscriptions_spec.rb @@ -1,26 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" describe :stripe_subscription do - it 'creates a plan if none provided' do + it "creates a plan if none provided" do subscription = create(:stripe_subscription) - expect {Stripe::Plan.retrieve(subscription.plan.id)}.to_not raise_error + expect { Stripe::Plan.retrieve(subscription.plan.id) }.to_not raise_error end - it 'creates a customer if none provided' do + it "creates a customer if none provided" do subscription = create(:stripe_subscription) - expect {Stripe::Customer.retrieve(subscription.customer)}.to_not raise_error + expect { Stripe::Customer.retrieve(subscription.customer) }.to_not raise_error end - it 'uses a custom plan if provided' do + it "uses a custom plan if provided" do provided_plan = create(:stripe_plan_base) subscription = create(:stripe_subscription, stripe_plan: provided_plan) expect(subscription.plan).to eq provided_plan - end - it 'uses a custom customer if provided' do + it "uses a custom customer if provided" do provided_customer = create(:stripe_customer_base) subscription = create(:stripe_subscription, stripe_customer: provided_customer) expect(subscription.customer).to eq provided_customer.id end -end \ No newline at end of file +end diff --git a/spec/factory_specs/stripe/stripe_tokens_spec.rb b/spec/factory_specs/stripe/stripe_tokens_spec.rb index 3fbc3afd6..72483c6f2 100644 --- a/spec/factory_specs/stripe/stripe_tokens_spec.rb +++ b/spec/factory_specs/stripe/stripe_tokens_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" describe :stripe_token do - it 'provides a Stripe::Token' do + it "provides a Stripe::Token" do token = create(:stripe_token) expect(token).to be_a Stripe::Token end - it 'can be retrieved if requested' do + it "can be retrieved if requested" do token = create(:stripe_token) server_token = Stripe::Token.retrieve(token.id) expect(token).to eq server_token end -end \ No newline at end of file +end diff --git a/spec/factory_specs/transactions_spec.rb b/spec/factory_specs/transactions_spec.rb index efc808870..900a0b194 100644 --- a/spec/factory_specs/transactions_spec.rb +++ b/spec/factory_specs/transactions_spec.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -describe 'transactions factories' do +describe "transactions factories" do describe :transaction_base do def create_legacy_donation create(:legacy_payment_base, :with_offline_donation).donation @@ -12,60 +12,59 @@ def create_trx create(:transaction_base, legacy_donation: legacy_donation, legacy_payments: legacy_donation.payment, supporter: legacy_donation.supporter) end - it 'creates one payment' do + it "creates one payment" do create_trx expect(Payment.count).to eq 1 end - it 'creates one Donation' do + it "creates one Donation" do create_trx expect(Donation.count).to eq 1 end - it 'creates one Nonprofit' do + it "creates one Nonprofit" do create_trx expect(Nonprofit.count).to eq 1 end - it 'creates one Supporter' do + it "creates one Supporter" do create_trx expect(Supporter.count).to eq 1 end - it 'creates one OffsitePayment' do + it "creates one OffsitePayment" do create_trx expect(OffsitePayment.count).to eq 1 end - it 'creates one TransactionAssignment' do + it "creates one TransactionAssignment" do create_trx expect(TransactionAssignment.count).to eq 1 end - it 'creates one ModernDonation' do + it "creates one ModernDonation" do create_trx expect(ModernDonation.count).to eq 1 end - it 'creates one Subtransaction' do + it "creates one Subtransaction" do create_trx expect(Subtransaction.count).to eq 1 end - it 'creates one OfflineTransaction' do + it "creates one OfflineTransaction" do create_trx expect(OfflineTransaction.count).to eq 1 end - it 'creates one SubtransactionPayment' do + it "creates one SubtransactionPayment" do create_trx expect(SubtransactionPayment.count).to eq 1 end - it 'creates one OfflineTransactionCharge' do + it "creates one OfflineTransactionCharge" do create_trx expect(OfflineTransactionCharge.count).to eq 1 end - end -end \ No newline at end of file +end diff --git a/spec/helpers/devise_helper_spec.rb b/spec/helpers/devise_helper_spec.rb index a8567328b..a89e12730 100644 --- a/spec/helpers/devise_helper_spec.rb +++ b/spec/helpers/devise_helper_spec.rb @@ -3,9 +3,9 @@ RSpec.describe DeviseHelper, type: :helper do describe "#devise_error_messages!" do - let(:valid_user) { build(:user_base)} - let(:invalid_user) { build(:user_base, email: "invaliduser", password: "not the same as", password_confirmation: "confirmation")} - + let(:valid_user) { build(:user_base) } + let(:invalid_user) { build(:user_base, email: "invaliduser", password: "not the same as", password_confirmation: "confirmation") } + it "returns nil when no error" do assign(:resource, valid_user) valid_user.save diff --git a/spec/jobs/inline/modern_object_donation_stripe_charge_job_spec.rb b/spec/jobs/inline/modern_object_donation_stripe_charge_job_spec.rb index 5e0d66537..9d1328919 100644 --- a/spec/jobs/inline/modern_object_donation_stripe_charge_job_spec.rb +++ b/spec/jobs/inline/modern_object_donation_stripe_charge_job_spec.rb @@ -1,40 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe InlineJob::ModernObjectDonationStripeChargeJob, type: :job do - + let(:nonprofit) { force_create(:nonprofit, statement: "swhtowht", name: "atata") } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } - let(:nonprofit) { force_create(:nonprofit, statement:'swhtowht', name: 'atata')} - let(:supporter) {force_create(:supporter, nonprofit:nonprofit)} - - let(:stripe_cust_id) { "cus_123455"} - let(:stripe_card_id) {"card_1234555"} + let(:stripe_cust_id) { "cus_123455" } + let(:stripe_card_id) { "card_1234555" } let(:card) { force_create(:card, holder: supporter, stripe_customer_id: stripe_cust_id, stripe_card_id: stripe_card_id) } - let(:donation) {force_create(:donation, supporter: supporter, amount: 300, card: card, nonprofit: nonprofit)} - let(:recurring_donation) { force_create(:recurring_donation, donation: donation, start_date: Time.now - 1.day, active:true, nonprofit: nonprofit, n_failures: 0, interval: 1, time_unit: 'month')} + let(:donation) { force_create(:donation, supporter: supporter, amount: 300, card: card, nonprofit: nonprofit) } + let(:recurring_donation) { force_create(:recurring_donation, donation: donation, start_date: Time.now - 1.day, active: true, nonprofit: nonprofit, n_failures: 0, interval: 1, time_unit: "month") } let(:misc_recurring_donation_info__covered) { force_create(:misc_recurring_donation_info, recurring_donation: recurring_donation, fee_covered: true) } - let(:recent_charge) {force_create(:charge, donation:donation, card:card, amount: 300, status:'paid', created_at: Time.now - 1.day, payment: recent_payment)} + let(:recent_charge) { force_create(:charge, donation: donation, card: card, amount: 300, status: "paid", created_at: Time.now - 1.day, payment: recent_payment) } - let(:recent_payment) { force_create(:payment, gross_amount: 300, date: Time.now - 1.day, supporter: supporter)} + let(:recent_payment) { force_create(:payment, gross_amount: 300, date: Time.now - 1.day, supporter: supporter) } let(:performed_job) { InlineJob::ModernObjectDonationStripeChargeJob.perform_now(legacy_payment: recent_charge.payment, donation: donation) } it { - expect{ performed_job }.to change { Transaction.count }.by(1) + expect { performed_job }.to change { Transaction.count }.by(1) } it { - expect{ performed_job }.to change { SubtransactionPayment.count }.by(1) + expect { performed_job }.to change { SubtransactionPayment.count }.by(1) } it { - expect{ performed_job }.to change { StripeTransactionCharge.count }.by(1) + expect { performed_job }.to change { StripeTransactionCharge.count }.by(1) } it { @@ -42,11 +40,9 @@ } it { - expect{ performed_job }.to change { ModernDonation.last&.legacy_donation }.to(donation) + expect { performed_job }.to change { ModernDonation.last&.legacy_donation }.to(donation) } it { - expect { performed_job }.to change {nonprofit.associated_object_events.event_types('stripe_transaction_charge.created').count }.by(1) + expect { performed_job }.to change { nonprofit.associated_object_events.event_types("stripe_transaction_charge.created").count }.by(1) } - - end diff --git a/spec/jobs/mailchimp_nonprofit_user_add_job_spec.rb b/spec/jobs/mailchimp_nonprofit_user_add_job_spec.rb index 2057d2f1e..0b60edecf 100644 --- a/spec/jobs/mailchimp_nonprofit_user_add_job_spec.rb +++ b/spec/jobs/mailchimp_nonprofit_user_add_job_spec.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe MailchimpNonprofitUserAddJob, type: :job do - let(:user) {create(:user)} - let(:nonprofit) {create(:nonprofit_base)} - let(:drip_email_list) {create(:drip_email_list_base)} + let(:user) { create(:user) } + let(:nonprofit) { create(:nonprofit_base) } + let(:drip_email_list) { create(:drip_email_list_base) } - it 'runs job' do + it "runs job" do expect(Mailchimp).to receive(:signup_nonprofit_user).with(drip_email_list, nonprofit, user) MailchimpNonprofitUserAddJob.perform_now(user, nonprofit) - end - + end end diff --git a/spec/jobs/mailchimp_signup_job_spec.rb b/spec/jobs/mailchimp_signup_job_spec.rb index c507bae72..ff0c1e633 100644 --- a/spec/jobs/mailchimp_signup_job_spec.rb +++ b/spec/jobs/mailchimp_signup_job_spec.rb @@ -1,16 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe MailchimpSignupJob, type: :job do - let(:mailchimp_list) { create(:email_list_base)} + let(:mailchimp_list) { create(:email_list_base) } let(:supporter) { create(:supporter) } - - it 'enqueues the job when provided with the correct email' do + it "enqueues the job when provided with the correct email" do expect(Mailchimp).to receive(:signup).with(supporter, mailchimp_list) MailchimpSignupJob.perform_now(supporter, mailchimp_list) - end - end diff --git a/spec/jobs/populate_list_job_spec.rb b/spec/jobs/populate_list_job_spec.rb index 0f0ab1b67..3d3246268 100644 --- a/spec/jobs/populate_list_job_spec.rb +++ b/spec/jobs/populate_list_job_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe PopulateListJob, type: :job do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/jobs/recurring_donation_cancelled_job_spec.rb b/spec/jobs/recurring_donation_cancelled_job_spec.rb index 5837fb0aa..ce243e075 100644 --- a/spec/jobs/recurring_donation_cancelled_job_spec.rb +++ b/spec/jobs/recurring_donation_cancelled_job_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe RecurringDonationCancelledJob, type: :job do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/jobs/recurring_donation_created_job_spec.rb b/spec/jobs/recurring_donation_created_job_spec.rb index 0fae4b74d..7df9a7a2f 100644 --- a/spec/jobs/recurring_donation_created_job_spec.rb +++ b/spec/jobs/recurring_donation_created_job_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe RecurringDonationCreatedJob, type: :job do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/lib/calculate/calculate_suggested_amounts_spec.rb b/spec/lib/calculate/calculate_suggested_amounts_spec.rb index 5e1c44e45..475418738 100644 --- a/spec/lib/calculate/calculate_suggested_amounts_spec.rb +++ b/spec/lib/calculate/calculate_suggested_amounts_spec.rb @@ -1,103 +1,102 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe CalculateSuggestedAmounts do - describe '.calculate' do - it 'param validation' do - expect { CalculateSuggestedAmounts.calculate(nil) }.to(raise_error {|error| + describe ".calculate" do + it "param validation" do + expect { CalculateSuggestedAmounts.calculate(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error, [{key: :amount, name: :required}, {key: :amount, name: :is_a}, {key: :amount, name: :min}, {key: :amount, name: :max}]) }) - expect { CalculateSuggestedAmounts.calculate("fffff") }.to(raise_error {|error| + expect { CalculateSuggestedAmounts.calculate("fffff") }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error, [{key: :amount, name: :is_a}, {key: :amount, name: :min}, {key: :amount, name: :max}]) }) end - it '1 gives you 2-4' do + it "1 gives you 2-4" do result = CalculateSuggestedAmounts.calculate(100) - expect(result).to eq([200,300,400]) + expect(result).to eq([200, 300, 400]) end - it '1.25 gives you 1, 2-4' do + it "1.25 gives you 1, 2-4" do result = CalculateSuggestedAmounts.calculate(125) - expect(result).to eq([100,200,300,400]) + expect(result).to eq([100, 200, 300, 400]) end - it '2 gives you 1, 3-5' do + it "2 gives you 1, 3-5" do result = CalculateSuggestedAmounts.calculate(200) expect(result).to eq([100, 300, 400, 500]) end - it '9 gives you 8, 10, 15,20' do + it "9 gives you 8, 10, 15,20" do result = CalculateSuggestedAmounts.calculate(900) - expect(result).to eq([800,1000,1500,2000]) + expect(result).to eq([800, 1000, 1500, 2000]) end - it '9.5 gives you 9, 10, 15,20' do + it "9.5 gives you 9, 10, 15,20" do result = CalculateSuggestedAmounts.calculate(950) - expect(result).to eq([900,1000,1500,2000]) + expect(result).to eq([900, 1000, 1500, 2000]) end - it '10 gives you 9, 15, 20, 25' do + it "10 gives you 9, 15, 20, 25" do result = CalculateSuggestedAmounts.calculate(1000) expect(result).to eq([900, 1500, 2000, 2500]) end - it '11 gives you 10, 15, 20, 25' do + it "11 gives you 10, 15, 20, 25" do result = CalculateSuggestedAmounts.calculate(1100) expect(result).to eq([1000, 1500, 2000, 2500]) end - it '35 gives you 30, 40, 45, 50' do + it "35 gives you 30, 40, 45, 50" do result = CalculateSuggestedAmounts.calculate(3500) expect(result).to eq([3000, 4000, 4500, 5000]) end - it '40 gives you 35, 45, 50, 75' do + it "40 gives you 35, 45, 50, 75" do result = CalculateSuggestedAmounts.calculate(4000) expect(result).to eq([3500, 4500, 5000, 7500]) end - it '43 gives you 40, 45, 50, 75' do + it "43 gives you 40, 45, 50, 75" do result = CalculateSuggestedAmounts.calculate(4300) expect(result).to eq([4000, 4500, 5000, 7500]) end - it '47 gives you 45, 50, 75, 100' do + it "47 gives you 45, 50, 75, 100" do result = CalculateSuggestedAmounts.calculate(4700) expect(result).to eq([4500, 5000, 7500, 10000]) end - it '47 gives you 45, 50, 75, 100' do + it "47 gives you 45, 50, 75, 100" do result = CalculateSuggestedAmounts.calculate(4700) expect(result).to eq([4500, 5000, 7500, 10000]) end - it '50 gives you 45, 75, 100, 125' do + it "50 gives you 45, 75, 100, 125" do result = CalculateSuggestedAmounts.calculate(5000) expect(result).to eq([4500, 7500, 10000, 12500]) end - it '65 gives you 50, 75, 100, 125' do + it "65 gives you 50, 75, 100, 125" do result = CalculateSuggestedAmounts.calculate(6500) expect(result).to eq([5000, 7500, 10000, 12500]) end - it '75 gives you 50, 100, 125, 150' do + it "75 gives you 50, 100, 125, 150" do result = CalculateSuggestedAmounts.calculate(7500) expect(result).to eq([5000, 10000, 12500, 15000]) end - it '999925 gives you 999900, 999950, 999975' do + it "999925 gives you 999900, 999950, 999975" do result = CalculateSuggestedAmounts.calculate(99992500) expect(result).to eq([99990000, 99995000, 99997500]) end - it '999950 gives you 999925, 999975' do + it "999950 gives you 999925, 999975" do result = CalculateSuggestedAmounts.calculate(99995000) expect(result).to eq([99992500, 99997500]) end - end -end \ No newline at end of file +end diff --git a/spec/lib/cancel_billing_subscriptions_spec.rb b/spec/lib/cancel_billing_subscriptions_spec.rb index 07e217d79..af9f69fe1 100644 --- a/spec/lib/cancel_billing_subscriptions_spec.rb +++ b/spec/lib/cancel_billing_subscriptions_spec.rb @@ -1,45 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe CancelBillingSubscription do - around(:each) do |example| StripeMockHelper.mock do example.run end end - - - describe 'parameter validation' do - describe 'with no parameters' do - it "has unprocessable status" do - + describe "parameter validation" do + describe "with no parameters" do + it "has unprocessable status" do result = CancelBillingSubscription.with_stripe(nil) - - expect(result[:status]).to eq :unprocessable_entity - - end it "has 2 validation errors" do # with_stripe_mock do - result = CancelBillingSubscription.with_stripe(nil) - errors = result[:json][:errors] - expect(errors.length).to eq(2) - expect_validation_errors(errors, [ - {key: :nonprofit, name: :required}, - {key: :nonprofit, name: :is_a} - ]) - + result = CancelBillingSubscription.with_stripe(nil) + errors = result[:json][:errors] + expect(errors.length).to eq(2) + expect_validation_errors(errors, [ + {key: :nonprofit, name: :required}, + {key: :nonprofit, name: :is_a} + ]) end end - context 'with nonprofit' do - + context "with nonprofit" do def create_nonprofit_with_billing_subscription create(:nonprofit_base, :with_default_billing_subscription) end @@ -52,127 +42,123 @@ def create_nonprofit_with_billing_subscription_and_active_card create(:nonprofit_base, :with_default_billing_subscription, :with_active_card_on_stripe) end - it 'nonprofit valid but no card or billing_subscription' do + it "nonprofit valid but no card or billing_subscription" do nonprofit = create_nonprofit_without_billing_subscription result = CancelBillingSubscription.with_stripe(nonprofit) expect_proper_failure(result) end - - it 'nonprofit valid but no card' do + + it "nonprofit valid but no card" do nonprofit = create_nonprofit_with_billing_subscription result = CancelBillingSubscription.with_stripe(nonprofit) expect_proper_failure(result) end - it 'nonprofit valid but no billings subscription' do - nonprofit = create(:nonprofit_base, :with_active_card_on_stripe) + it "nonprofit valid but no billings subscription" do + nonprofit = create(:nonprofit_base, :with_active_card_on_stripe) result = CancelBillingSubscription.with_stripe(nonprofit) expect_proper_failure(result) end def expect_proper_failure(result) expect(result[:status]).to eq(:unprocessable_entity) - expect(result[:json][:error]).to start_with("We don\'t have a subscription for your non-profit. Please contact support.") + expect(result[:json][:error]).to start_with("We don't have a subscription for your non-profit. Please contact support.") end end - end - context 'processing the billing subscription' do + context "processing the billing subscription" do def create_nonprofit create(:nonprofit_base, :with_old_billing_plan_on_stripe) end def create_default_plan - create(:billing_plan_base, :with_associated_stripe_plan, :id => Settings.default_bp.id) + create(:billing_plan_base, :with_associated_stripe_plan, id: Settings.default_bp.id) end - describe 'with a failure' do + describe "with a failure" do def prepare_stripe_error - StripeMockHelper.prepare_error(Stripe::StripeError.new('some failure'), :retrieve_customer_subscription) + StripeMockHelper.prepare_error(Stripe::StripeError.new("some failure"), :retrieve_customer_subscription) end - it 'has a status of :unprocessable entity' do + it "has a status of :unprocessable entity" do np = create_nonprofit prepare_stripe_error - result = CancelBillingSubscription::with_stripe(np) + result = CancelBillingSubscription.with_stripe(np) expect(result[:status]).to eq :unprocessable_entity end - it 'has the correct error message ' do + it "has the correct error message " do np = create_nonprofit prepare_stripe_error - - result = CancelBillingSubscription::with_stripe(np) + + result = CancelBillingSubscription.with_stripe(np) expect(result[:json][:error]).to start_with("Oops") end - it 'hasnt changed the nonprofit\'s billing_subscription' do + it "hasnt changed the nonprofit's billing_subscription" do np = create_nonprofit prepare_stripe_error - - expect {CancelBillingSubscription::with_stripe(np) }.to_not change { np.reload.billing_subscription.reload} + + expect { CancelBillingSubscription.with_stripe(np) }.to_not change { np.reload.billing_subscription.reload } end - it 'hasn\'t changed the nonprofit Stripe customer subscription' do + it "hasn't changed the nonprofit Stripe customer subscription" do np = create_nonprofit prepare_stripe_error - expect {CancelBillingSubscription::with_stripe(np) }.to_not change { Stripe::Customer.retrieve(np.active_card.stripe_customer_id)} + expect { CancelBillingSubscription.with_stripe(np) }.to_not change { Stripe::Customer.retrieve(np.active_card.stripe_customer_id) } end end - describe 'successfully' do - - it 'has status :ok' do + describe "successfully" do + it "has status :ok" do np = create_nonprofit create_default_plan - result = CancelBillingSubscription::with_stripe(np) + result = CancelBillingSubscription.with_stripe(np) expect(result[:status]).to eq :ok end - it 'has empty json' do + it "has empty json" do np = create_nonprofit create_default_plan - result = CancelBillingSubscription::with_stripe(np) - expect(result[:json]).to eq Hash.new + result = CancelBillingSubscription.with_stripe(np) + expect(result[:json]).to eq({}) end - it 'has an active billing_subscription' do + it "has an active billing_subscription" do np = create_nonprofit create_default_plan - result = CancelBillingSubscription::with_stripe(np) - - expect(np.billing_subscription.status).to eq 'active' + CancelBillingSubscription.with_stripe(np) + + expect(np.billing_subscription.status).to eq "active" end - it 'changed billing_subscription to default' do + it "changed billing_subscription to default" do np = create_nonprofit default_plan = create_default_plan - expect {CancelBillingSubscription::with_stripe(np)}.to change{ np.billing_subscription.billing_plan }.to default_plan + expect { CancelBillingSubscription.with_stripe(np) }.to change { np.billing_subscription.billing_plan }.to default_plan end - it 'removed nonprofit\'s stripe customer subscriptions' do + it "removed nonprofit's stripe customer subscriptions" do np = create_nonprofit - default_plan = create_default_plan - expect {CancelBillingSubscription::with_stripe(np)}.to change { Stripe::Customer.retrieve(np.active_card.stripe_customer_id).subscriptions.data }.to [] + create_default_plan + expect { CancelBillingSubscription.with_stripe(np) }.to change { Stripe::Customer.retrieve(np.active_card.stripe_customer_id).subscriptions.data }.to [] end end - - # it 'should succeed' do # prepare # result = CancelBillingSubscription::with_stripe(@np) # expect(result[:status]).to eq :ok # expect(result[:json]).to eq Hash.new - # expect + # expect # expect(@np.billing_subscription.status).to eq 'active' # expect(@np.billing_subscription.billing_plan).to eq @default_plan # str_customer_reloaded = Stripe::Customer.retrieve(@np.active_card.stripe_customer_id) # expect(str_customer_reloaded.subscriptions.data.length).to eq 0 # end end -end \ No newline at end of file +end diff --git a/spec/lib/chunked_uploader/s3_spec.rb b/spec/lib/chunked_uploader/s3_spec.rb index 1256bb1b5..498022742 100644 --- a/spec/lib/chunked_uploader/s3_spec.rb +++ b/spec/lib/chunked_uploader/s3_spec.rb @@ -1,45 +1,45 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rspec' -require 'rails_helper' +require "rspec" +require "rails_helper" describe ChunkedUploader::S3 do - context '.upload' do - skip 'Only run this if you are okay getting billed on s3' do + context ".upload" do + skip "Only run this if you are okay getting billed on s3" do before(:each) do WebMock.disable! @s3 = Aws::S3.new - @bucket = @s3.buckets[ENV['S3_BUCKET_NAME']] - @path = 'tmp/export/1000000000.csv' + @bucket = @s3.buckets[ENV["S3_BUCKET_NAME"]] + @path = "tmp/export/1000000000.csv" @object = @bucket.objects[@path] end after(:each) do @object.delete WebMock.enable! end - it 'uploads empty properly' do - ChunkedUploader::S3.upload(@path, [], content_type: 'text/csv') + it "uploads empty properly" do + ChunkedUploader::S3.upload(@path, [], content_type: "text/csv") info = @object.read.to_s - expect(info).to eq('') + expect(info).to eq("") end - it 'uploads very small properly' do + it "uploads very small properly" do input = 'row11,row12\nrow21,row22\n' - ChunkedUploader::S3.upload(@path, [input], content_type: 'text/csv') + ChunkedUploader::S3.upload(@path, [input], content_type: "text/csv") info = @object.read.to_s expect(info).to eq(input) - pending('NOTE: METADATA CHECKING ISNT WORKING SO WE SKIP IT FOR NOW') + pending("NOTE: METADATA CHECKING ISNT WORKING SO WE SKIP IT FOR NOW") metadata = @object.metadata puts metadata - expect(metadata['Content-Type']).to eq('text/csv') + expect(metadata["Content-Type"]).to eq("text/csv") end - it 'uploads very large single properly' do + it "uploads very large single properly" do temp = StringIO.new 500_000.times { temp << 'row11,row12\n' } ChunkedUploader::S3.upload(@path, [temp.string]) @@ -48,12 +48,12 @@ expect(info).to eq(temp.string) - pending('NOTE: METADATA CHECKING ISNT WORKING SO WE SKIP IT FOR NOW') + pending("NOTE: METADATA CHECKING ISNT WORKING SO WE SKIP IT FOR NOW") metadata = @object.metadata - expect(metadata['Content-Type']).to eq('text/csv') + expect(metadata["Content-Type"]).to eq("text/csv") end - it 'uploads properly' do + it "uploads properly" do input_item = StringIO.new input = Enumerator.new do |y| temp = StringIO.new @@ -69,14 +69,14 @@ input_item.write(temp.string) y << temp.string end.lazy - ChunkedUploader::S3.upload(@path, input, content_type: 'text/csv') + ChunkedUploader::S3.upload(@path, input, content_type: "text/csv") info = @object.read.to_s expect(info).to eq(input_item.string) - pending('NOTE: METADATA CHECKING ISNT WORKING SO WE SKIP IT FOR NOW') + pending("NOTE: METADATA CHECKING ISNT WORKING SO WE SKIP IT FOR NOW") metadata = @object.metadata - expect(metadata['Content-Type']).to eq('text/csv') + expect(metadata["Content-Type"]).to eq("text/csv") end end end diff --git a/spec/lib/copy_naming_algorithm_spec.rb b/spec/lib/copy_naming_algorithm_spec.rb index 24d01cedd..b31a23b26 100644 --- a/spec/lib/copy_naming_algorithm_spec.rb +++ b/spec/lib/copy_naming_algorithm_spec.rb @@ -1,103 +1,101 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe CopyNamingAlgorithm do - describe '.create_copy_name' do - let(:base_name_short) {'b'} - let(:base_name_short_copy) { 'b_copy-00' } - let(:base_name_short_copy_1) { 'b_copy-01' } - let(:base_name_short_copy_2) { 'b_copy-02' } - - let(:base_name_long) {'ten digits'} - let(:base_name_long_copy) {'te_copy-00'} - let(:base_name_long_copy_1) {'te_copy-01'} - let(:base_name_long_copy_2) {'te_copy-02'} - - - it 'create copy when none exist already' do + describe ".create_copy_name" do + let(:base_name_short) { "b" } + let(:base_name_short_copy) { "b_copy-00" } + let(:base_name_short_copy_1) { "b_copy-01" } + let(:base_name_short_copy_2) { "b_copy-02" } + + let(:base_name_long) { "ten digits" } + let(:base_name_long_copy) { "te_copy-00" } + let(:base_name_long_copy_1) { "te_copy-01" } + let(:base_name_long_copy_2) { "te_copy-02" } + + it "create copy when none exist already" do names = [base_name_short] - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_short) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_short) expect(result).to eq base_name_short_copy end - it 'create copy when one exists already' do + it "create copy when one exists already" do names = [base_name_short, base_name_short_copy] - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_short) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_short) expect(result).to eq base_name_short_copy_1 - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_short_copy) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_short_copy) expect(result).to eq base_name_short_copy_1 end - it 'create copy when two exist already' do + it "create copy when two exist already" do names = [base_name_short, base_name_short_copy, base_name_short_copy_1] - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_short) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_short) expect(result).to eq base_name_short_copy_2 - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_short_copy) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_short_copy) expect(result).to eq base_name_short_copy_2 - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_short_copy_1) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_short_copy_1) expect(result).to eq base_name_short_copy_2 - end - it 'create copy when none exists - longer' do + it "create copy when none exists - longer" do names = [base_name_long] - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_long) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_long) expect(result).to eq base_name_long_copy end - it 'create copy when one exists - longer' do + it "create copy when one exists - longer" do names = [base_name_long, base_name_long_copy] - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_long) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_long) expect(result).to eq base_name_long_copy_1 - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_long_copy) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_long_copy) expect(result).to eq base_name_long_copy_1 end - it 'create copy when two exists - longer' do + it "create copy when two exists - longer" do names = [base_name_long, base_name_long_copy, base_name_long_copy_1] - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_long) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_long) expect(result).to eq base_name_long_copy_2 - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_long_copy) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_long_copy) expect(result).to eq base_name_long_copy_2 - result = TestCopyNamingAlgorithm.new(name_entities:names).create_copy_name(base_name_long_copy_1) + result = TestCopyNamingAlgorithm.new(name_entities: names).create_copy_name(base_name_long_copy_1) expect(result).to eq base_name_long_copy_2 end - it 'raises ArgumentError on length limit problem' do - names = ['c'] - expect{ TestCopyNamingAlgorithm.new(name_entities:names, max_length:4).create_copy_name(names[0]) }.to(raise_error {|e| + it "raises ArgumentError on length limit problem" do + names = ["c"] + expect { TestCopyNamingAlgorithm.new(name_entities: names, max_length: 4).create_copy_name(names[0]) }.to(raise_error { |e| expect(e).to be_a ArgumentError expect(e.message).to start_with("It's not possible to generate a name using name_to_copy:") }) end - it 'raises ArgumentError on copy limit problem' do - names = ['c', 'c_copy-0'] - expect{ TestCopyNamingAlgorithm.new(name_entities:names, max_copies:1).create_copy_name(names[0]) }.to(raise_error {|e| + it "raises ArgumentError on copy limit problem" do + names = ["c", "c_copy-0"] + expect { TestCopyNamingAlgorithm.new(name_entities: names, max_copies: 1).create_copy_name(names[0]) }.to(raise_error { |e| expect(e).to be_a ArgumentError expect(e.message).to start_with("It's not possible to generate a UNIQUE name using name_to_copy:") }) end end - describe '.generate_copy_number' do - it 'adds one digit for copy number if under 10' do - algo = TestCopyNamingAlgorithm.new(max_copies:9) - (0..9).each{|i| + describe ".generate_copy_number" do + it "adds one digit for copy number if under 10" do + algo = TestCopyNamingAlgorithm.new(max_copies: 9) + (0..9).each { |i| expect(algo.generate_copy_number(i)).to eq "#{i}" } end - it 'adds 2 digits for copy number if under 100' do - algo = TestCopyNamingAlgorithm.new(max_copies:99) - (0..99).each{|i| - if (i < 10) + it "adds 2 digits for copy number if under 100" do + algo = TestCopyNamingAlgorithm.new(max_copies: 99) + (0..99).each { |i| + if i < 10 expect(algo.generate_copy_number(i)).to eq "0#{i}" else expect(algo.generate_copy_number(i)).to eq "#{i}" @@ -105,12 +103,12 @@ } end - it 'adds 3 digits for copy number if under 1000' do - algo = TestCopyNamingAlgorithm.new(max_copies:999) - (0..999).each{|i| - if (i < 10) + it "adds 3 digits for copy number if under 1000" do + algo = TestCopyNamingAlgorithm.new(max_copies: 999) + (0..999).each { |i| + if i < 10 expect(algo.generate_copy_number(i)).to eq "00#{i}" - elsif (i >= 10 && i < 100) + elsif i >= 10 && i < 100 expect(algo.generate_copy_number(i)).to eq "0#{i}" else expect(algo.generate_copy_number(i)).to eq "#{i}" @@ -122,31 +120,26 @@ class TestCopyNamingAlgorithm < CopyNamingAlgorithm attr_accessor :name_entities, :max_copies, :max_length - def initialize(name_entities:[], max_length:10, max_copies: 20) + def initialize(name_entities: [], max_length: 10, max_copies: 20) @name_entities = name_entities @max_copies = max_copies @max_length = max_length end def copy_addition - '_copy' + "_copy" end def separator_before_copy_number - '-' + "-" end - def max_length - @max_length - end + attr_reader :max_length def get_already_used_name_entities(base_name) @name_entities end - def max_copies - @max_copies - end + attr_reader :max_copies end end - diff --git a/spec/lib/core_ext/string_spec.rb b/spec/lib/core_ext/string_spec.rb index f7527a1fc..0b6473145 100644 --- a/spec/lib/core_ext/string_spec.rb +++ b/spec/lib/core_ext/string_spec.rb @@ -1,22 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'core_ext/string' +require "core_ext/string" describe String do - describe '#is_int?' do - it { - expect("5".is_int?).to be true - } + describe "#is_int?" do + it { + expect("5".is_int?).to be true + } - it { - expect("5.41".is_int?).to be false - } + it { + expect("5.41".is_int?).to be false + } - it { - expect("a".is_int?).to be false - } + it { + expect("a".is_int?).to be false + } - it { - expect("1_a_string_with_non_digits_in-between-digits_5".is_int?).to be false - } + it { + expect("1_a_string_with_non_digits_in-between-digits_5".is_int?).to be false + } end -end \ No newline at end of file +end diff --git a/spec/lib/create_campaign_gift_spec.rb b/spec/lib/create_campaign_gift_spec.rb index f7c45925a..12e9a565e 100644 --- a/spec/lib/create_campaign_gift_spec.rb +++ b/spec/lib/create_campaign_gift_spec.rb @@ -1,140 +1,128 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe CreateCampaignGift do - - describe '.create' do - before(:each){ - ##stub out the mailing stuff used by campaign creation + describe ".create" do + before(:each) { + # #stub out the mailing stuff used by campaign creation cm = double(CampaignMailer) allow(cm).to receive(:creation_followup) nam = double(NonprofitAdminMailer) allow(nam).to receive(:supporter_fundraiser) allow(CampaignMailer).to receive(:delay).and_return(cm) allow(NonprofitAdminMailer).to receive(:delay).and_return(nam) - } - describe 'param validation' do - let (:donation) { force_create(:donation)} - it 'basic validation' do - expect { CreateCampaignGift.create({}) }.to(raise_error {|error| - expect(error).to be_a(ParamValidation::ValidationError) + describe "param validation" do + let(:donation) { force_create(:donation) } + it "basic validation" do + expect { CreateCampaignGift.create({}) }.to(raise_error { |error| + expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error.data, [{ - :key => :campaign_gift_option_id, - :name => :required - }, - { - :key => :campaign_gift_option_id, - :name => :is_integer - }, - { - :key => :donation_id, - :name => :required - }, - { - :key => :donation_id, - :name => :is_integer - }]) + key: :campaign_gift_option_id, + name: :required + }, + { + key: :campaign_gift_option_id, + name: :is_integer + }, + { + key: :donation_id, + name: :required + }, + { + key: :donation_id, + name: :is_integer + }]) }) end - it 'validates donation exists' do - expect {CreateCampaignGift.create({:donation_id => 555, :campaign_gift_option_id => 5555}) }.to(raise_error {|error| + it "validates donation exists" do + expect { CreateCampaignGift.create({donation_id: 555, campaign_gift_option_id: 5555}) }.to(raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, {:key => :donation_id}) - expect(error.message).to eq ('555 is not a valid donation id.') + expect_validation_errors(error.data, {key: :donation_id}) + expect(error.message).to eq("555 is not a valid donation id.") }) end - it 'validates campaign gift option exists' do - expect {CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => 5555}) }.to(raise_error {|error| - expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, {:key => :campaign_gift_option_id}) - expect(error.message).to eq ('5555 is not a valid campaign gift option') - }) + it "validates campaign gift option exists" do + expect { CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: 5555}) }.to(raise_error { |error| + expect(error).to be_a(ParamValidation::ValidationError) + expect_validation_errors(error.data, {key: :campaign_gift_option_id}) + expect(error.message).to eq("5555 is not a valid campaign gift option") + }) end - describe 'donation and campaign gift option exist so we validate the details' do + describe "donation and campaign gift option exist so we validate the details" do + let(:profile) { force_create(:profile, user: force_create(:user)) } + let(:nonprofit) { force_create(:nonprofit) } + let(:campaign) { force_create(:campaign, profile: profile, nonprofit: nonprofit) } + let(:bad_campaign) { force_create(:campaign, profile: profile, nonprofit: nonprofit) } + let(:billing_plan) { force_create(:billing_plan, percentage_fee: 0.05) } + let(:billing_subscription) { force_create(:billing_subscription, nonprofit: nonprofit, billing_plan: billing_plan) } - - let(:profile) {force_create(:profile, :user => force_create(:user))} - let(:nonprofit) {force_create(:nonprofit)} - let(:campaign) { force_create(:campaign, :profile => profile, nonprofit: nonprofit)} - let(:bad_campaign) {force_create(:campaign, :profile => profile, nonprofit: nonprofit)} - - let(:billing_plan) { force_create(:billing_plan, percentage_fee: 0.05)} - let(:billing_subscription) {force_create(:billing_subscription, nonprofit: nonprofit, billing_plan: billing_plan)} - - - it 'rejects adding multiple gift options' do - donation = force_create(:donation,nonprofit: nonprofit ) + it "rejects adding multiple gift options" do + donation = force_create(:donation, nonprofit: nonprofit) campaign_gift_option = force_create(:campaign_gift_option, campaign: campaign) billing_subscription - force_create(:campaign_gift, :donation => donation) - expect { CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) }.to raise_error {|error| - expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, {:key => :donation_id}) - expect(error.message).to eq ("#{donation.id} already has at least one associated campaign gift") + force_create(:campaign_gift, donation: donation) + expect { CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) }.to raise_error { |error| + expect(error).to be_a(ParamValidation::ValidationError) + expect_validation_errors(error.data, {key: :donation_id}) + expect(error.message).to eq("#{donation.id} already has at least one associated campaign gift") } end - it 'rejects adding a gift option when the gift option campaign and donation campaign dont match' do - - donation = force_create(:donation, nonprofit: nonprofit, :campaign => campaign) - campaign_gift_option = force_create(:campaign_gift_option, :campaign => bad_campaign) + it "rejects adding a gift option when the gift option campaign and donation campaign dont match" do + donation = force_create(:donation, nonprofit: nonprofit, campaign: campaign) + campaign_gift_option = force_create(:campaign_gift_option, campaign: bad_campaign) profile campaign bad_campaign billing_subscription - expect { CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) }.to raise_error {|error| + expect { CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) }.to raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, {:key => :campaign_gift_option_id}) - expect(error.message).to eq ("#{campaign_gift_option.id} is not for the same campaign as donation #{donation.id}") + expect_validation_errors(error.data, {key: :campaign_gift_option_id}) + expect(error.message).to eq("#{campaign_gift_option.id} is not for the same campaign as donation #{donation.id}") } - - end - it 'rejects associations when the donation amount is too low' do + it "rejects associations when the donation amount is too low" do adm = double(AdminMailer) billing_subscription - - donation = force_create(:donation, :campaign => campaign, nonprofit: nonprofit, :amount => 299) - payment = force_create(:payment, donation_id: donation.id, gross_amount: 299) - campaign_gift_option = force_create(:campaign_gift_option, :campaign => campaign, :amount_one_time => 300, :name=> "name") + + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 299) + force_create(:payment, donation_id: donation.id, gross_amount: 299) + campaign_gift_option = force_create(:campaign_gift_option, campaign: campaign, amount_one_time: 300, name: "name") expect(adm).to receive(:notify_failed_gift).with(donation, kind_of(Payment), campaign_gift_option) expect(AdminMailer).to receive(:delay).and_return(adm) - expect { CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) }.to raise_error {|error| + expect { CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) }.to raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, {:key => :campaign_gift_option_id}) - expect(error.message).to eq ("#{campaign_gift_option.id} gift options requires a donation of 300 for donation #{donation.id}") + expect_validation_errors(error.data, {key: :campaign_gift_option_id}) + expect(error.message).to eq("#{campaign_gift_option.id} gift options requires a donation of 300 for donation #{donation.id}") } end - it 'rejects associations when the recurring donation amount is too low' do - + it "rejects associations when the recurring donation amount is too low" do adm = double(AdminMailer) billing_subscription - donation = force_create(:donation, :campaign => campaign, nonprofit: nonprofit, :amount => 299, :recurring=> true) - payment = force_create(:payment, donation_id: donation.id, gross_amount: 299) - rd = force_create(:recurring_donation, :amount => 299, :donation => donation) - campaign_gift_option = force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :name=> "name") - + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 299, recurring: true) + force_create(:payment, donation_id: donation.id, gross_amount: 299) + force_create(:recurring_donation, amount: 299, donation: donation) + campaign_gift_option = force_create(:campaign_gift_option, campaign: campaign, amount_recurring: 300, name: "name") expect(adm).to receive(:notify_failed_gift).with(donation, kind_of(Payment), campaign_gift_option) expect(AdminMailer).to receive(:delay).and_return(adm) - expect { CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) }.to raise_error {|error| + expect { CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) }.to raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, {:key => :campaign_gift_option_id}) - expect(error.message).to eq ("#{campaign_gift_option.id} gift options requires a recurring donation of 300 for donation #{donation.id}") + expect_validation_errors(error.data, {key: :campaign_gift_option_id}) + expect(error.message).to eq("#{campaign_gift_option.id} gift options requires a recurring donation of 300 for donation #{donation.id}") } end - # it 'rejects associations when the recurring donation amount is not correct' do # adm = double(AdminMailer) @@ -144,7 +132,6 @@ # rd = force_create(:recurring_donation, :amount => 500, :donation => donation) # campaign_gift_option = force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :name=> "name") - # expect(adm).to receive(:notify_failed_gift).with(donation, campaign_gift_option) # expect(AdminMailer).to receive(:delay).and_return(adm) # expect { CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) }.to raise_error {|error| @@ -154,48 +141,46 @@ # } # end - it 'rejects association when the there are no gifts available' do + it "rejects association when the there are no gifts available" do adm = double(AdminMailer) billing_subscription - - donation = force_create(:donation, :campaign => campaign, nonprofit: nonprofit, :amount => 300, :recurring=> true) - payment = force_create(:payment, donation_id: donation.id, gross_amount: 300) - rd = force_create(:recurring_donation, :amount => 300, :donation => donation) - campaign_gift_option = force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :quantity => 1) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 300, recurring: true) + force_create(:payment, donation_id: donation.id, gross_amount: 300) + force_create(:recurring_donation, amount: 300, donation: donation) + + campaign_gift_option = force_create(:campaign_gift_option, campaign: campaign, amount_recurring: 300, quantity: 1) expect(adm).to receive(:notify_failed_gift).with(donation, kind_of(Payment), campaign_gift_option) expect(AdminMailer).to receive(:delay).and_return(adm) - campaign_gift = force_create(:campaign_gift, :campaign_gift_option => campaign_gift_option) + force_create(:campaign_gift, campaign_gift_option: campaign_gift_option) - expect { CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) }.to raise_error {|error| + expect { CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) }.to raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error.data, [{:key => :campaign_gift_option_id}]) + expect_validation_errors(error.data, [{key: :campaign_gift_option_id}]) expect(error.message).to eq "#{campaign_gift_option.id} has no more inventory" expect(CampaignGift.count).to eq 1 } end end - end - describe 'successful insert' do - let(:nonprofit) {force_create(:nonprofit)} - let(:profile) {force_create(:profile, :user => force_create(:user))} - let(:campaign) { force_create(:campaign, :profile => profile)} - let(:billing_plan) { force_create(:billing_plan, percentage_fee: 0.05)} - let(:billing_subscription) {force_create(:billing_subscription, nonprofit: nonprofit, billing_plan: billing_plan)} - + describe "successful insert" do + let(:nonprofit) { force_create(:nonprofit) } + let(:profile) { force_create(:profile, user: force_create(:user)) } + let(:campaign) { force_create(:campaign, profile: profile) } + let(:billing_plan) { force_create(:billing_plan, percentage_fee: 0.05) } + let(:billing_subscription) { force_create(:billing_subscription, nonprofit: nonprofit, billing_plan: billing_plan) } - describe 'insert with no option quantity limit' do - let(:campaign_gift_option) { force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :amount_one_time => 5000)} + describe "insert with no option quantity limit" do + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, amount_recurring: 300, amount_one_time: 5000) } - it 'inserts non_recurring properly' do + it "inserts non_recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 5000) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 5000) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -203,12 +188,12 @@ end end - it 'inserts recurring properly' do + it "inserts recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 300) - rd = force_create(:recurring_donation, :amount => 300, :donation => donation) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 300) + force_create(:recurring_donation, amount: 300, donation: donation) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -217,14 +202,14 @@ end end - describe 'insert when option quantity is 0' do - let(:campaign_gift_option) { force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :amount_one_time => 5000, :quantity => 0)} + describe "insert when option quantity is 0" do + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, amount_recurring: 300, amount_one_time: 5000, quantity: 0) } - it 'inserts non_recurring properly' do + it "inserts non_recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 5000) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 5000) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -232,12 +217,12 @@ end end - it 'inserts recurring properly' do + it "inserts recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 300) - rd = force_create(:recurring_donation, :amount => 300, :donation => donation) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 300) + force_create(:recurring_donation, amount: 300, donation: donation) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -246,14 +231,14 @@ end end - describe 'insert when option inventory is less than quantity total' do - let(:campaign_gift_option) { force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :amount_one_time => 5000, :quantity => 1)} + describe "insert when option inventory is less than quantity total" do + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, amount_recurring: 300, amount_one_time: 5000, quantity: 1) } - it 'inserts non_recurring properly' do + it "inserts non_recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 5000) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 5000) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -261,12 +246,12 @@ end end - it 'inserts recurring properly' do + it "inserts recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 300) - rd = force_create(:recurring_donation, :amount => 300, :donation => donation) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 300) + force_create(:recurring_donation, amount: 300, donation: donation) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -275,14 +260,14 @@ end end - describe 'insert when option quantity is 0' do - let(:campaign_gift_option) { force_create(:campaign_gift_option, :campaign => campaign, :amount_recurring => 300, :amount_one_time => 5000, :quantity => 0)} + describe "insert when option quantity is 0" do + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, amount_recurring: 300, amount_one_time: 5000, quantity: 0) } - it 'inserts non_recurring properly' do + it "inserts non_recurring properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :nonprofit => nonprofit, :amount => 5000) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, nonprofit: nonprofit, amount: 5000) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -290,12 +275,12 @@ end end - it 'inserts when using fee coverage properly' do + it "inserts when using fee coverage properly" do Timecop.freeze(2020, 4, 5) do billing_subscription - donation = force_create(:donation, :campaign => campaign, :amount => 356, :nonprofit => nonprofit) - rd = force_create(:recurring_donation, :amount => 356, :donation => donation) - result = CreateCampaignGift.create({:donation_id => donation.id, :campaign_gift_option_id => campaign_gift_option.id}) + donation = force_create(:donation, campaign: campaign, amount: 356, nonprofit: nonprofit) + force_create(:recurring_donation, amount: 356, donation: donation) + result = CreateCampaignGift.create({donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id}) expected = {donation_id: donation.id, campaign_gift_option_id: campaign_gift_option.id, created_at: Time.now, updated_at: Time.now, id: result.id, recurring_donation_id: nil}.with_indifferent_access expect(result.attributes).to eq expected expect(CampaignGift.first.attributes).to eq expected @@ -304,5 +289,5 @@ end end end - end + end end diff --git a/spec/lib/create_peer_to_peer_campaign_spec.rb b/spec/lib/create_peer_to_peer_campaign_spec.rb index 0cfc34f16..4c8c5a92d 100644 --- a/spec/lib/create_peer_to_peer_campaign_spec.rb +++ b/spec/lib/create_peer_to_peer_campaign_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe CreatePeerToPeerCampaign do - describe '.create' do - let!(:profile) { force_create(:profile, :user => force_create(:user)) } - let!(:parent_campaign) { force_create(:campaign, name: 'Parent campaign') } + describe ".create" do + let!(:profile) { force_create(:profile, user: force_create(:user)) } + let!(:parent_campaign) { force_create(:campaign, name: "Parent campaign") } - context 'on success' do - it 'returns a hash' do - campaign_params = { name: 'Child campaign', parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000" } + context "on success" do + it "returns a hash" do + campaign_params = {name: "Child campaign", parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000"} Timecop.freeze(2020, 4, 5) do result = CreatePeerToPeerCampaign.create(campaign_params, profile.id) @@ -16,54 +16,54 @@ end end - it 'returns created peer-to-peer campaign' do - campaign_params = { name: 'Child campaign', parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000" } + it "returns created peer-to-peer campaign" do + campaign_params = {name: "Child campaign", parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000"} Timecop.freeze(2020, 4, 5) do result = CreatePeerToPeerCampaign.create(campaign_params, profile.id) - expect(result).not_to include 'errors' - expect(result['parent_campaign_id']).to eq parent_campaign.id - expect(result['created_at']).to eq '2020-04-05T00:00:00.000Z' + expect(result).not_to include "errors" + expect(result["parent_campaign_id"]).to eq parent_campaign.id + expect(result["created_at"]).to eq "2020-04-05T00:00:00.000Z" end end - it 'assigns proper slug' do - campaign_params = { name: 'Child campaign', parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000" } + it "assigns proper slug" do + campaign_params = {name: "Child campaign", parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000"} Timecop.freeze(2020, 4, 5) do result = CreatePeerToPeerCampaign.create(campaign_params, profile.id) - expect(result).not_to include 'errors' - expect(result['slug']).to eq 'child-campaign_000' + expect(result).not_to include "errors" + expect(result["slug"]).to eq "child-campaign_000" end end - it 'saves campaign' do - campaign_params = { name: 'Child campaign', parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000" } + it "saves campaign" do + campaign_params = {name: "Child campaign", parent_campaign_id: parent_campaign.id, goal_amount_dollars: "1000"} Timecop.freeze(2020, 4, 5) do expect { CreatePeerToPeerCampaign.create(campaign_params, profile.id) }.to change(Campaign, :count).by 1 end end end - context 'on failure' do + context "on failure" do it "returns an error if parent campaign can't be found" do campaign_params = {} Timecop.freeze(2020, 4, 5) do result = CreatePeerToPeerCampaign.create(campaign_params, profile.id) expect(result).to be_kind_of Hash - expect(result['errors']['parent_campaign_id']).to eq 'not found' + expect(result["errors"]["parent_campaign_id"]).to eq "not found" end end - it 'returns a list of error messages for attribute validation' do - campaign_params = { parent_campaign_id: parent_campaign.id } + it "returns a list of error messages for attribute validation" do + campaign_params = {parent_campaign_id: parent_campaign.id} Timecop.freeze(2020, 4, 5) do result = CreatePeerToPeerCampaign.create(campaign_params, profile.id) expect(result).to be_kind_of Hash - expect(result).to include 'errors' - expect(result['errors']['goal_amount']).to match ["can't be blank", 'is not a number', 'must be greater than or equal to 99 cents'] + expect(result).to include "errors" + expect(result["errors"]["goal_amount"]).to match ["can't be blank", "is not a number", "must be greater than or equal to 99 cents"] end end diff --git a/spec/lib/delete/delete_campaign_gift_option_spec.rb b/spec/lib/delete/delete_campaign_gift_option_spec.rb index 15120e27c..9577fd07a 100644 --- a/spec/lib/delete/delete_campaign_gift_option_spec.rb +++ b/spec/lib/delete/delete_campaign_gift_option_spec.rb @@ -1,78 +1,78 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe DeleteCampaignGiftOption do - before(:each){ - ##stub out the mailing stuff used by campaign creation + before(:each) { + # #stub out the mailing stuff used by campaign creation cm = double(CampaignMailer) allow(cm).to receive(:creation_followup) nam = double(NonprofitAdminMailer) allow(nam).to receive(:supporter_fundraiser) allow(CampaignMailer).to receive(:delay).and_return(cm) allow(NonprofitAdminMailer).to receive(:delay).and_return(nam) - } - describe '.delete' do - let(:profile) {force_create(:profile, :user => force_create(:user))} - let(:campaign) { force_create(:campaign, :profile => profile)} - let(:campaign_gift_option) { force_create(:campaign_gift_option, :campaign => campaign)} - let(:campaign_gift) { force_create(:campaign_gift, :campaign_gift_option => campaign_gift_option)} - describe 'param validation' do - - it 'does basic validation' do - expect{ DeleteCampaignGiftOption.delete(nil, - nil)} - .to(raise_error{|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [ + describe ".delete" do + let(:profile) { force_create(:profile, user: force_create(:user)) } + let(:campaign) { force_create(:campaign, profile: profile) } + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign) } + let(:campaign_gift) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option) } + describe "param validation" do + it "does basic validation" do + expect { + DeleteCampaignGiftOption.delete(nil, + nil) + } + .to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, [ { - :key => :campaign, - :name => :required + key: :campaign, + name: :required }, { - :key => :campaign, - :name => :is_a + key: :campaign, + name: :is_a }, { - :key => :campaign_gift_option_id, - :name => :required + key: :campaign_gift_option_id, + name: :required }, { - :key => :campaign_gift_option_id, - :name => :is_integer + key: :campaign_gift_option_id, + name: :is_integer } - ]) - }) + ]) + }) end - it 'does cgo verification' do - expect { DeleteCampaignGiftOption.delete(campaign, 5555)}.to(raise_error{|error| + it "does cgo verification" do + expect { DeleteCampaignGiftOption.delete(campaign, 5555) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [{:key => :campaign_gift_option_id}]) + expect_validation_errors(error.data, [{key: :campaign_gift_option_id}]) }) end end - it 'cgo deletion is rejected because a gift has already been sold' do + it "cgo deletion is rejected because a gift has already been sold" do campaign_gift_option campaign_gift - expect { DeleteCampaignGiftOption.delete(campaign, campaign_gift_option.id)}.to(raise_error{|error| + expect { DeleteCampaignGiftOption.delete(campaign, campaign_gift_option.id) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [{:key => :campaign_gift_option_id}]) + expect_validation_errors(error.data, [{key: :campaign_gift_option_id}]) expect(error.message).to eq("#{campaign_gift_option.id} already has campaign gifts. It can't be deleted for safety reasons.") expect(CampaignGiftOption.any?).to eq true }) end - it 'cgo deletion succeeds' do - Timecop.freeze(2020,10,12) do + it "cgo deletion succeeds" do + Timecop.freeze(2020, 10, 12) do campaign_gift_option result = DeleteCampaignGiftOption.delete(campaign, campaign_gift_option.id) expect(result).to be_a CampaignGiftOption - expect(result.attributes).to eq (campaign_gift_option.attributes) + expect(result.attributes).to eq(campaign_gift_option.attributes) expect(CampaignGiftOption.any?).to eq false end end end -end \ No newline at end of file +end diff --git a/spec/lib/export/export_payments_spec.rb b/spec/lib/export/export_payments_spec.rb index 257cb5aae..3bb0ee542 100644 --- a/spec/lib/export/export_payments_spec.rb +++ b/spec/lib/export/export_payments_spec.rb @@ -1,41 +1,45 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'support/test_chunked_uploader' +require "rails_helper" +require "support/test_chunked_uploader" describe ExportPayments do before(:each) do - stub_const('CHUNKED_UPLOADER',TestChunkedUploader) - + stub_const("CHUNKED_UPLOADER", TestChunkedUploader) + CHUNKED_UPLOADER.clear end - let(:email) { 'example@example.com'} - let(:user) {force_create(:user, email: email)} + let(:email) { "example@example.com" } + let(:user) { force_create(:user, email: email) } let(:nonprofit) { force_create(:nonprofit) } - let(:supporters) { [ force_create(:supporter, name: "supporter-0", nonprofit: nonprofit), - force_create(:supporter, name: "supporter-1", nonprofit: nonprofit)]} - let(:payments) {[force_create(:payment, gross_amount: 1000, fee_total: 99, net_amount: 901, supporter: supporters[0], nonprofit:nonprofit), - force_create(:payment, gross_amount: 2000, fee_total: 22, net_amount: 1978, supporter: supporters[1], nonprofit:nonprofit)]} + let(:supporters) { + [force_create(:supporter, name: "supporter-0", nonprofit: nonprofit), + force_create(:supporter, name: "supporter-1", nonprofit: nonprofit)] + } + let(:payments) { + [force_create(:payment, gross_amount: 1000, fee_total: 99, net_amount: 901, supporter: supporters[0], nonprofit: nonprofit), + force_create(:payment, gross_amount: 2000, fee_total: 22, net_amount: 1978, supporter: supporters[1], nonprofit: nonprofit)] + } before(:each) { - payments + payments } - context '.initiate_export' do - context 'param verification' do - it 'performs initial verification' do + context ".initiate_export" do + context "param verification" do + it "performs initial verification" do expect { ExportPayments.initiate_export(nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect(error.data.length).to eq(6) - expect_validation_errors(error.data, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_hash }]) + expect_validation_errors(error.data, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_hash}]) end) end - it 'nonprofit doesnt exist' do + it "nonprofit doesnt exist" do fake_npo = 8_888_881 expect { ExportPayments.initiate_export(fake_npo, {}, 8_888_883) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -43,7 +47,7 @@ end) end - it 'user doesnt exist' do + it "user doesnt exist" do fake_user = 8_888_883 expect { ExportPayments.initiate_export(nonprofit.id, {}, fake_user) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -52,78 +56,78 @@ end end - it 'creates an export object and schedules job' do + it "creates an export object and schedules job" do Timecop.freeze(2020, 4, 5) do - stub_const("DelayedJobHelper", double('delayed')) - params = { param1: 'pp' }.with_indifferent_access + stub_const("DelayedJobHelper", double("delayed")) + params = {param1: "pp"}.with_indifferent_access - expect(Export).to receive(:create).and_wrap_original {|m, *args| + expect(Export).to receive(:create).and_wrap_original { |m, *args| e = m.call(*args) # get original create - expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportPayments, :run_export, [nonprofit.id, params.to_json, user.id, e.id]) #add the enqueue + expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportPayments, :run_export, [nonprofit.id, params.to_json, user.id, e.id]) # add the enqueue e } ExportPayments.initiate_export(nonprofit.id, params, user.id) export = Export.first - expected_export = { id: export.id, - user_id: user.id, - nonprofit_id: nonprofit.id, - status: 'queued', - export_type: 'ExportPayments', - parameters: params.to_json, - updated_at: Time.now, - created_at: Time.now, - url: nil, - ended: nil, - exception: nil }.with_indifferent_access + expected_export = {id: export.id, + user_id: user.id, + nonprofit_id: nonprofit.id, + status: "queued", + export_type: "ExportPayments", + parameters: params.to_json, + updated_at: Time.now, + created_at: Time.now, + url: nil, + ended: nil, + exception: nil}.with_indifferent_access expect(export.attributes).to eq(expected_export) end end end - context '.run_export' do - context 'param validation' do - it 'rejects basic invalid data' do + context ".run_export" do + context "param validation" do + it "rejects basic invalid data" do expect { ExportPayments.run_export(nil, nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_json }, - { key: 'export_id', name: :required }, - { key: 'export_id', name: :is_integer }]) + expect_validation_errors(error, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_json}, + {key: "export_id", name: :required}, + {key: "export_id", name: :is_integer}]) end) end - it 'rejects json which isnt a hash' do - expect { ExportPayments.run_export(1, [{ item: '' }, { item: '' }].to_json, 1, 1) }.to(raise_error do |error| + it "rejects json which isnt a hash" do + expect { ExportPayments.run_export(1, [{item: ""}, {item: ""}].to_json, 1, 1) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error, [ - { key: :params, name: :is_hash } - ]) + {key: :params, name: :is_hash} + ]) end) end - it 'no export throw an exception' do - expect { ExportPayments.run_export(0, { x: 1 }.to_json, 0, 11_111) }.to(raise_error do |error| + it "no export throw an exception" do + expect { ExportPayments.run_export(0, {x: 1}.to_json, 0, 11_111) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :export_id - expect(error.message).to start_with('Export') + expect(error.message).to start_with("Export") end) end - it 'no nonprofit' do + it "no nonprofit" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: user) Timecop.freeze(2020, 4, 6) do - expect { ExportPayments.run_export(0, { x: 1 }.to_json, user.id, @export.id) }.to(raise_error do |error| + expect { ExportPayments.run_export(0, {x: 1}.to_json, user.id, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :npo_id - expect(error.message).to start_with('Nonprofit') + expect(error.message).to start_with("Nonprofit") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now @@ -134,29 +138,27 @@ end end - it 'no user' do + it "no user" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: user) Timecop.freeze(2020, 4, 6) do - expect { ExportPayments.run_export(nonprofit.id, { x: 1 }.to_json, 0, @export.id) }.to(raise_error do |error| + expect { ExportPayments.run_export(nonprofit.id, {x: 1}.to_json, 0, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :user_id - expect(error.message).to start_with('User') + expect(error.message).to start_with("User") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now - - end) end end end end - it 'handles exception in upload properly' do + it "handles exception in upload properly" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: user) CHUNKED_UPLOADER.raise_error @@ -166,7 +168,7 @@ expect(error.message).to eq TestChunkedUploader::TEST_ERROR_MESSAGE @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now @@ -177,7 +179,7 @@ end end - it 'uploads as expected' do + it "uploads as expected" do Timecop.freeze(2020, 4, 5) do @export = create(:export, user: user, created_at: Time.now, updated_at: Time.now) Timecop.freeze(2020, 4, 6, 1, 2, 3) do @@ -186,94 +188,95 @@ @export.reload expect(@export.url).to eq "http://fake.url/tmp/csv-exports/payments-#{@export.id}-04-06-2020--01-02-03.csv" - expect(@export.status).to eq 'completed' + expect(@export.status).to eq "completed" expect(@export.exception).to be_nil expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now csv = CSV.parse(TestChunkedUploader.output) - expect(csv.length).to eq (3) + expect(csv.length).to eq(3) expect(csv[0]).to eq MockHelpers.payment_export_headers - expect(TestChunkedUploader.options[:content_type]).to eq 'text/csv' - expect(TestChunkedUploader.options[:content_disposition]).to eq 'attachment' + expect(TestChunkedUploader.options[:content_type]).to eq "text/csv" + expect(TestChunkedUploader.options[:content_disposition]).to eq "attachment" expect(user).to have_received_email(subject: "Your payment export is available!") end end end end - describe '.for_export_enumerable' do - it 'finishes two payment export' do + describe ".for_export_enumerable" do + it "finishes two payment export" do rows = ExportPayments.for_export_enumerable(nonprofit.id, {}).to_a headers = MockHelpers.payment_export_headers expect(rows.length).to eq(3) expect(rows[0]).to eq(headers) - end - context 'includes proper anonymous value' do + context "includes proper anonymous value" do include_context :shared_rd_donation_value_context before(:each) do - nonprofit.stripe_account_id = Stripe::Account.create()['id'] + nonprofit.stripe_account_id = Stripe::Account.create["id"] nonprofit.save! - cust = Stripe::Customer.create() + cust = Stripe::Customer.create card.stripe_customer_id = cust.id - source = Stripe::Customer.create_source(cust.id, {source: StripeMockHelper.generate_card_token(brand: 'Visa', country: 'US')}) + source = Stripe::Customer.create_source(cust.id, {source: StripeMockHelper.generate_card_token(brand: "Visa", country: "US")}) card.stripe_card_id = source.id card.save! - allow(Stripe::Charge).to receive(:create).and_wrap_original {|m, *args| a = m.call(*args); - @stripe_charge_id = a['id'] + allow(Stripe::Charge).to receive(:create).and_wrap_original { |m, *args| + a = m.call(*args) + @stripe_charge_id = a["id"] a } - end - let(:input) {{ - amount: 100, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - token: source_tokens[4].token, - date: (Time.now - 1.day).to_s, - comment: 'donation comment', - designation: 'designation' - }} - - it 'is not anonymous when neither donation nor supporter are' do + let(:input) { + { + amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + token: source_tokens[4].token, + date: (Time.now - 1.day).to_s, + comment: "donation comment", + designation: "designation" + } + } + + it "is not anonymous when neither donation nor supporter are" do InsertDonation.with_stripe(input) - result = ExportPayments.for_export_enumerable(nonprofit.id, { search: Payment.last.id }).to_a - row = CSV.parse(Format::Csv.from_array(result), headers:true).first + result = ExportPayments.for_export_enumerable(nonprofit.id, {search: Payment.last.id}).to_a + row = CSV.parse(Format::Csv.from_array(result), headers: true).first expect(row["Anonymous?"]).to eq "false" end - it 'is anonymous when donation is' do + it "is anonymous when donation is" do InsertDonation.with_stripe(input) d = Donation.last d.anonymous = true d.save! - result = ExportPayments.for_export_enumerable(nonprofit.id, { search: Payment.last.id }).to_a - row = CSV.parse(Format::Csv.from_array(result), headers:true).first + result = ExportPayments.for_export_enumerable(nonprofit.id, {search: Payment.last.id}).to_a + row = CSV.parse(Format::Csv.from_array(result), headers: true).first expect(row["Anonymous?"]).to eq "true" end - it 'is anonymous when supporter is' do + it "is anonymous when supporter is" do InsertDonation.with_stripe(input) s = Payment.last.supporter s.anonymous = true s.save! - - result = ExportPayments.for_export_enumerable(nonprofit.id, { search: Payment.last.id }).to_a - row = CSV.parse(Format::Csv.from_array(result.to_a), headers:true).first + + result = ExportPayments.for_export_enumerable(nonprofit.id, {search: Payment.last.id}).to_a + row = CSV.parse(Format::Csv.from_array(result.to_a), headers: true).first expect(row["Anonymous?"]).to eq "true" end end - context 'when export_format' do + context "when export_format" do around(:each) do |e| Timecop.freeze(2021, 10, 26) do e.run @@ -282,66 +285,66 @@ before do Payment.find_each do |p| - p.kind = 'RecurringDonation' + p.kind = "RecurringDonation" p.date = Time.zone.now p.save! end end - context 'when there is an export_format for that export' do + context "when there is an export_format for that export" do let(:export_format) do nonprofit.export_formats.create( - name: 'CiviCRM format', - date_format: 'MM/DD/YYYY', + name: "CiviCRM format", + date_format: "MM/DD/YYYY", show_currency: false, custom_columns_and_values: { - 'payments.kind' => { - 'custom_values' => { - 'RecurringDonation' => 'Recurring Donation' + "payments.kind" => { + "custom_values" => { + "RecurringDonation" => "Recurring Donation" }, - 'custom_name' => 'Kind of Payment' + "custom_name" => "Kind of Payment" } } ) end - let(:export_result) { ExportPayments.for_export_enumerable(nonprofit.id, { export_format_id: export_format.id }).to_a } + let(:export_result) { ExportPayments.for_export_enumerable(nonprofit.id, {export_format_id: export_format.id}).to_a } subject do CSV.parse( Format::Csv.from_array( export_result ), - headers:true + headers: true ).first.to_h end it 'changes the default "type" column for "Kind of Payment"' do - expect(subject.include?('Kind Of Payment')).to be_truthy + expect(subject.include?("Kind Of Payment")).to be_truthy end - it 'customizes the payment.kind RecurringDonation value to be Recurring Donation' do - expect(subject['Kind Of Payment']).to eq('Recurring Donation') + it "customizes the payment.kind RecurringDonation value to be Recurring Donation" do + expect(subject["Kind Of Payment"]).to eq("Recurring Donation") end - it 'does not show currency on payments.gross_amount' do - expect(subject['Gross Amount'].include?('$')).to be_falsy + it "does not show currency on payments.gross_amount" do + expect(subject["Gross Amount"].include?("$")).to be_falsy end - it 'does not show currency on payments.fee_total' do - expect(subject['Fee Total'].include?('$')).to be_falsy + it "does not show currency on payments.fee_total" do + expect(subject["Fee Total"].include?("$")).to be_falsy end - it 'does not show currency on payments.net_amount' do - expect(subject['Net Amount'].include?('$')).to be_falsy + it "does not show currency on payments.net_amount" do + expect(subject["Net Amount"].include?("$")).to be_falsy end - it 'follows the desired date format' do - expect(subject['Date']).to eq('10/26/2021') + it "follows the desired date format" do + expect(subject["Date"]).to eq("10/26/2021") end - context 'when the export_format does not specify any custom values or names' do - it 'does not change any header' do + context "when the export_format does not specify any custom values or names" do + it "does not change any header" do export_format.custom_columns_and_values = nil export_format.save! headers = MockHelpers.payment_export_headers @@ -350,44 +353,43 @@ end end - context 'when there is not an export_format for that export, relies on our default format' do - let(:export_result) { ExportPayments.for_export_enumerable(nonprofit.id, { }).to_a } + context "when there is not an export_format for that export, relies on our default format" do + let(:export_result) { ExportPayments.for_export_enumerable(nonprofit.id, {}).to_a } subject do CSV.parse( Format::Csv.from_array( export_result ), - headers:true + headers: true ).first.to_h end - it 'does not change any header' do + it "does not change any header" do headers = MockHelpers.payment_export_headers expect(export_result[0]).to eq(headers) end - it 'reflects payment.kind RecurringDonation to be the same as our database' do - expect(subject['Type']).to eq('RecurringDonation') + it "reflects payment.kind RecurringDonation to be the same as our database" do + expect(subject["Type"]).to eq("RecurringDonation") end - it 'shows currency on payments.gross_amount' do - expect(subject['Gross Amount'].include?('$')).to be_truthy + it "shows currency on payments.gross_amount" do + expect(subject["Gross Amount"].include?("$")).to be_truthy end - it 'shows currency on payments.fee_total' do - expect(subject['Fee Total'].include?('$')).to be_truthy + it "shows currency on payments.fee_total" do + expect(subject["Fee Total"].include?("$")).to be_truthy end - it 'shows currency on payments.net_amount' do - expect(subject['Net Amount'].include?('$')).to be_truthy + it "shows currency on payments.net_amount" do + expect(subject["Net Amount"].include?("$")).to be_truthy end - it 'shows our default date format' do - expect(subject['Date']).to eq('2021-10-26 00:00:00 ') + it "shows our default date format" do + expect(subject["Date"]).to eq("2021-10-26 00:00:00 ") end end end end end - diff --git a/spec/lib/export/export_recurring_donations_spec.rb b/spec/lib/export/export_recurring_donations_spec.rb index 5c7e0bff3..5903b1e69 100644 --- a/spec/lib/export/export_recurring_donations_spec.rb +++ b/spec/lib/export/export_recurring_donations_spec.rb @@ -1,38 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'support/test_chunked_uploader' +require "rails_helper" +require "support/test_chunked_uploader" describe ExportRecurringDonations do before(:each) do - stub_const('CHUNKED_UPLOADER',TestChunkedUploader) - @email = 'example@example.com' + stub_const("CHUNKED_UPLOADER", TestChunkedUploader) + @email = "example@example.com" @user = force_create(:user, email: @email) @nonprofit = force_create(:nonprofit) - @supporters = [ force_create(:supporter, name: "supporter-0", nonprofit: @nonprofit), - force_create(:supporter, name: "supporter-1", nonprofit: @nonprofit)] + @supporters = [force_create(:supporter, name: "supporter-0", nonprofit: @nonprofit), + force_create(:supporter, name: "supporter-1", nonprofit: @nonprofit)] @donations = [force_create(:donation, nonprofit: @nonprofit, supporter: @supporters[0]), - force_create(:donation, nonprofit: @nonprofit, supporter: @supporters[1])] - @recurring_donations = [force_create(:recurring_donation, donation: @donations[0], nonprofit:@nonprofit, edit_token: 'edit_token_1', active:true), - force_create(:recurring_donation, donation: @donations[1], supporter: @supporters[1], nonprofit:@nonprofit, edit_token: 'edit_token_2', active:true)] + force_create(:donation, nonprofit: @nonprofit, supporter: @supporters[1])] + @recurring_donations = [force_create(:recurring_donation, donation: @donations[0], nonprofit: @nonprofit, edit_token: "edit_token_1", active: true), + force_create(:recurring_donation, donation: @donations[1], supporter: @supporters[1], nonprofit: @nonprofit, edit_token: "edit_token_2", active: true)] CHUNKED_UPLOADER.clear end - context '.initiate_export' do - context 'param verification' do - it 'performs initial verification' do + context ".initiate_export" do + context "param verification" do + it "performs initial verification" do expect { ExportRecurringDonations.initiate_export(nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect(error.data.length).to eq(6) - expect_validation_errors(error.data, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_ids', name: :required }, - { key: 'user_ids', name: :is_array }, - { key: 'params', name: :required }, - { key: 'params', name: :is_hash }]) + expect_validation_errors(error.data, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_ids", name: :required}, + {key: "user_ids", name: :is_array}, + {key: "params", name: :required}, + {key: "params", name: :is_hash}]) end) end - it 'nonprofit doesnt exist' do + it "nonprofit doesnt exist" do fake_npo = 8_888_881 expect { ExportRecurringDonations.initiate_export(fake_npo, {}, [123]) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -40,7 +40,7 @@ end) end - it 'user doesnt exist' do + it "user doesnt exist" do fake_user = 8_888_883 expect { ExportRecurringDonations.initiate_export(@nonprofit.id, {}, [fake_user]) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -49,112 +49,109 @@ end end - it 'creates an export object and schedules job' do + it "creates an export object and schedules job" do Timecop.freeze(2020, 4, 5) do - stub_const("DelayedJobHelper", double('delayed')) - params = { param1: 'pp', root_url: 'https://localhost:8080' }.with_indifferent_access + stub_const("DelayedJobHelper", double("delayed")) + params = {param1: "pp", root_url: "https://localhost:8080"}.with_indifferent_access - expect(Export).to receive(:create).and_wrap_original {|m, *args| + expect(Export).to receive(:create).and_wrap_original { |m, *args| e = m.call(*args) # get original create - expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportRecurringDonations, :run_export, [@nonprofit.id, params.to_json, @user.id, e.id, :requested_by_user_through_ui]) #add the enqueue + expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportRecurringDonations, :run_export, [@nonprofit.id, params.to_json, @user.id, e.id, :requested_by_user_through_ui]) # add the enqueue e } - ExportRecurringDonations.initiate_export(@nonprofit.id, params, [@user.id]) export = Export.first - expected_export = { id: export.id, - user_id: @user.id, - nonprofit_id: @nonprofit.id, - status: 'queued', - export_type: 'ExportRecurringDonations', - parameters: params.to_json, - updated_at: Time.now, - created_at: Time.now, - url: nil, - ended: nil, - exception: nil }.with_indifferent_access + expected_export = {id: export.id, + user_id: @user.id, + nonprofit_id: @nonprofit.id, + status: "queued", + export_type: "ExportRecurringDonations", + parameters: params.to_json, + updated_at: Time.now, + created_at: Time.now, + url: nil, + ended: nil, + exception: nil}.with_indifferent_access expect(export.attributes).to eq(expected_export) end end end - context '.run_export' do - context 'param validation' do - it 'rejects basic invalid data' do + context ".run_export" do + context "param validation" do + it "rejects basic invalid data" do expect { ExportRecurringDonations.run_export(nil, nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_json }, - { key: 'export_id', name: :required }, - { key: 'export_id', name: :is_integer }]) + expect_validation_errors(error, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_json}, + {key: "export_id", name: :required}, + {key: "export_id", name: :is_integer}]) end) end - it 'rejects json which isnt a hash' do - expect { ExportRecurringDonations.run_export(1, [{ item: '' }, { item: '' }].to_json, 1, 1) }.to(raise_error do |error| + it "rejects json which isnt a hash" do + expect { ExportRecurringDonations.run_export(1, [{item: ""}, {item: ""}].to_json, 1, 1) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error, [ - { key: :params, name: :is_hash } - ]) + {key: :params, name: :is_hash} + ]) end) end - it 'no export throw an exception' do - expect { ExportRecurringDonations.run_export(0, { x: 1 }.to_json, 0, 11_111) }.to(raise_error do |error| + it "no export throw an exception" do + expect { ExportRecurringDonations.run_export(0, {x: 1}.to_json, 0, 11_111) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :export_id - expect(error.message).to start_with('Export') + expect(error.message).to start_with("Export") end) end - it 'no nonprofit' do + it "no nonprofit" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: @user) Timecop.freeze(2020, 4, 6) do - expect { ExportRecurringDonations.run_export(0, { x: 1 }.to_json, @user.id, @export.id) }.to(raise_error do |error| + expect { ExportRecurringDonations.run_export(0, {x: 1}.to_json, @user.id, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :npo_id - expect(error.message).to start_with('Nonprofit') + expect(error.message).to start_with("Nonprofit") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now - #expect(@user).to have_received_email(subject: "Your payment export has failed") + # expect(@user).to have_received_email(subject: "Your payment export has failed") end) end end end - it 'no user' do + it "no user" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: @user) Timecop.freeze(2020, 4, 6) do - expect { ExportRecurringDonations.run_export(@nonprofit.id, { x: 1 }.to_json, 0, @export.id) }.to(raise_error do |error| + expect { ExportRecurringDonations.run_export(@nonprofit.id, {x: 1}.to_json, 0, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :user_id - expect(error.message).to start_with('User') + expect(error.message).to start_with("User") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now - - end) end end end end - it 'handles exception in upload properly' do + it "handles exception in upload properly" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: @user) CHUNKED_UPLOADER.raise_error @@ -164,7 +161,7 @@ expect(error.message).to eq TestChunkedUploader::TEST_ERROR_MESSAGE @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now @@ -175,30 +172,29 @@ end end - it 'uploads as expected' do + it "uploads as expected" do Timecop.freeze(2020, 4, 5) do @export = create(:export, user: @user, created_at: Time.now, updated_at: Time.now) Timecop.freeze(2020, 4, 6, 1, 2, 3) do - ExportRecurringDonations.run_export(@nonprofit.id, {:root_url => "https://localhost:8080/"}.to_json, @user.id, @export.id) + ExportRecurringDonations.run_export(@nonprofit.id, {root_url: "https://localhost:8080/"}.to_json, @user.id, @export.id) @export.reload expect(@export.url).to eq "http://fake.url/tmp/csv-exports/recurring_donations-#{@export.id}-04-06-2020--01-02-03.csv" - expect(@export.status).to eq 'completed' + expect(@export.status).to eq "completed" expect(@export.exception).to be_nil expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now csv = CSV.parse(TestChunkedUploader.output) - expect(csv.length).to eq (3) + expect(csv.length).to eq(3) expect(csv[0]).to eq MockHelpers.recurring_donation_export_headers - expect(TestChunkedUploader.options[:content_type]).to eq 'text/csv' - expect(TestChunkedUploader.options[:content_disposition]).to eq 'attachment' + expect(TestChunkedUploader.options[:content_type]).to eq "text/csv" + expect(TestChunkedUploader.options[:content_disposition]).to eq "attachment" expect(@user).to have_received_email(subject: "Your recurring donations export is available!") end end end end end - diff --git a/spec/lib/export/export_supporter_notes_spec.rb b/spec/lib/export/export_supporter_notes_spec.rb index d1d1a8458..273ea6770 100644 --- a/spec/lib/export/export_supporter_notes_spec.rb +++ b/spec/lib/export/export_supporter_notes_spec.rb @@ -1,25 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'support/test_chunked_uploader' +require "rails_helper" +require "support/test_chunked_uploader" describe ExportSupporterNotes do before(:each) do - stub_const('CHUNKED_UPLOADER',TestChunkedUploader) + stub_const("CHUNKED_UPLOADER", TestChunkedUploader) supporter_note_for_s1 supporter_note_1_for_s2 supporter_note_2_for_s2 CHUNKED_UPLOADER.clear - end - let(:nonprofit) { force_create(:nonprofit)} - let(:supporter1) { force_create(:supporter, nonprofit: nonprofit)} - let(:supporter2) { force_create(:supporter, nonprofit: nonprofit)} + let(:nonprofit) { force_create(:nonprofit) } + let(:supporter1) { force_create(:supporter, nonprofit: nonprofit) } + let(:supporter2) { force_create(:supporter, nonprofit: nonprofit) } let(:user) { force_create(:user, email: email) } - let(:email) {'example@example.com'} + let(:email) { "example@example.com" } - let(:export_header) { ['Id', 'Email', 'Note Created At', 'Note Contents']} + let(:export_header) { ["Id", "Email", "Note Created At", "Note Contents"] } let(:note_content_1) do "CONTENT1" @@ -34,34 +33,33 @@ end let(:supporter_note_for_s1) do - force_create(:supporter_note, supporter: supporter1, created_at: DateTime.new(2018,1,5), content: note_content_1) + force_create(:supporter_note, supporter: supporter1, created_at: DateTime.new(2018, 1, 5), content: note_content_1) end let(:supporter_note_1_for_s2) do - force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2018,2,5), content: note_content_2) + force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2018, 2, 5), content: note_content_2) end let(:supporter_note_2_for_s2) do - force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2020,4, 5), content: note_content_3) + force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2020, 4, 5), content: note_content_3) end - - context '.initiate_export' do - context 'param verification' do - it 'performs initial verification' do + context ".initiate_export" do + context "param verification" do + it "performs initial verification" do expect { ExportSupporterNotes.initiate_export(nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect(error.data.length).to eq(6) - expect_validation_errors(error.data, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_hash }]) + expect_validation_errors(error.data, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_hash}]) end) end - it 'nonprofit doesnt exist' do + it "nonprofit doesnt exist" do fake_npo = 8_888_881 expect { ExportSupporterNotes.initiate_export(fake_npo, {}, 8_888_883) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -69,7 +67,7 @@ end) end - it 'user doesnt exist' do + it "user doesnt exist" do fake_user = 8_888_883 expect { ExportSupporterNotes.initiate_export(nonprofit.id, {}, fake_user) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -78,100 +76,98 @@ end end - it 'creates an export object and schedules job' do + it "creates an export object and schedules job" do Timecop.freeze(2020, 4, 5) do - stub_const("DelayedJobHelper",double('delayed')) - params = { param1: 'pp', root_url: 'https://localhost:8080' }.with_indifferent_access + stub_const("DelayedJobHelper", double("delayed")) + params = {param1: "pp", root_url: "https://localhost:8080"}.with_indifferent_access - expect(Export).to receive(:create).and_wrap_original {|m, *args| + expect(Export).to receive(:create).and_wrap_original { |m, *args| e = m.call(*args) # get original create - expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportSupporterNotes, :run_export, [nonprofit.id, params.to_json, user.id, e.id]) #add the enqueue + expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportSupporterNotes, :run_export, [nonprofit.id, params.to_json, user.id, e.id]) # add the enqueue e } - ExportSupporterNotes.initiate_export(nonprofit.id, params, user.id) export = Export.first - expected_export = { id: export.id, - user_id: user.id, - nonprofit_id: nonprofit.id, - status: 'queued', - export_type: 'ExportSupporterNotes', - parameters: params.to_json, - updated_at: Time.now, - created_at: Time.now, - url: nil, - ended: nil, - exception: nil }.with_indifferent_access + expected_export = {id: export.id, + user_id: user.id, + nonprofit_id: nonprofit.id, + status: "queued", + export_type: "ExportSupporterNotes", + parameters: params.to_json, + updated_at: Time.now, + created_at: Time.now, + url: nil, + ended: nil, + exception: nil}.with_indifferent_access expect(export.attributes).to eq(expected_export) end end end - context '.run_export' do - context 'param validation' do - it 'rejects basic invalid data' do + context ".run_export" do + context "param validation" do + it "rejects basic invalid data" do expect { ExportSupporterNotes.run_export(nil, nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_json }, - { key: 'export_id', name: :required }, - { key: 'export_id', name: :is_integer }]) + expect_validation_errors(error, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_json}, + {key: "export_id", name: :required}, + {key: "export_id", name: :is_integer}]) end) end - it 'rejects json which isnt a hash' do - expect { ExportSupporterNotes.run_export(1, [{ item: '' }, { item: '' }].to_json, 1, 1) }.to(raise_error do |error| + it "rejects json which isnt a hash" do + expect { ExportSupporterNotes.run_export(1, [{item: ""}, {item: ""}].to_json, 1, 1) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error, [ - { key: :params, name: :is_hash } + {key: :params, name: :is_hash} ]) end) end - it 'no export throw an exception' do - expect { ExportSupporterNotes.run_export(0, { x: 1 }.to_json, 0, 11_111) }.to(raise_error do |error| + it "no export throw an exception" do + expect { ExportSupporterNotes.run_export(0, {x: 1}.to_json, 0, 11_111) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :export_id - expect(error.message).to start_with('Export') + expect(error.message).to start_with("Export") end) end - it 'no nonprofit' do + it "no nonprofit" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: user) Timecop.freeze(2020, 4, 6) do - expect { ExportSupporterNotes.run_export(0, { x: 1 }.to_json, user.id, @export.id) }.to(raise_error do |error| + expect { ExportSupporterNotes.run_export(0, {x: 1}.to_json, user.id, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :npo_id - expect(error.message).to start_with('Nonprofit') + expect(error.message).to start_with("Nonprofit") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now - end) end end end - it 'no user' do + it "no user" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: user) Timecop.freeze(2020, 4, 6) do - expect { ExportSupporterNotes.run_export(nonprofit.id, { x: 1 }.to_json, 0, @export.id) }.to(raise_error do |error| + expect { ExportSupporterNotes.run_export(nonprofit.id, {x: 1}.to_json, 0, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :user_id - expect(error.message).to start_with('User') + expect(error.message).to start_with("User") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now @@ -181,7 +177,7 @@ end end - it 'handles exception in upload properly' do + it "handles exception in upload properly" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: user) expect_job_queued.with(JobTypes::ExportSupporterNotesFailedJob, @export) @@ -192,41 +188,38 @@ expect(error.message).to eq TestChunkedUploader::TEST_ERROR_MESSAGE @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now - - end) end end end - it 'uploads as expected' do + it "uploads as expected" do Timecop.freeze(2020, 4, 5) do @export = create(:export, user: user, created_at: Time.now, updated_at: Time.now) expect_job_queued.with(JobTypes::ExportSupporterNotesCompletedJob, @export) Timecop.freeze(2020, 4, 6, 1, 2, 3) do - ExportSupporterNotes.run_export(nonprofit.id, {:root_url => "https://localhost:8080/"}.to_json, user.id, @export.id) + ExportSupporterNotes.run_export(nonprofit.id, {root_url: "https://localhost:8080/"}.to_json, user.id, @export.id) @export.reload expect(@export.url).to eq "http://fake.url/tmp/csv-exports/supporters-notes-#{@export.id}-04-06-2020--01-02-03.csv" - expect(@export.status).to eq 'completed' + expect(@export.status).to eq "completed" expect(@export.exception).to be_nil expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now csv = CSV.parse(TestChunkedUploader.output) - expect(csv.length).to eq (4) + expect(csv.length).to eq(4) expect(csv[0]).to eq export_header - expect(TestChunkedUploader.options[:content_type]).to eq 'text/csv' - expect(TestChunkedUploader.options[:content_disposition]).to eq 'attachment' - + expect(TestChunkedUploader.options[:content_type]).to eq "text/csv" + expect(TestChunkedUploader.options[:content_disposition]).to eq "attachment" end end end end -end \ No newline at end of file +end diff --git a/spec/lib/export/export_supporters_spec.rb b/spec/lib/export/export_supporters_spec.rb index 99a54249a..9af7e0c92 100644 --- a/spec/lib/export/export_supporters_spec.rb +++ b/spec/lib/export/export_supporters_spec.rb @@ -1,34 +1,34 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'support/test_chunked_uploader' +require "rails_helper" +require "support/test_chunked_uploader" describe ExportSupporters do before(:each) do - stub_const('CHUNKED_UPLOADER',TestChunkedUploader) + stub_const("CHUNKED_UPLOADER", TestChunkedUploader) @nonprofit = force_create(:nonprofit) - @email = 'example@example.com' + @email = "example@example.com" @user = force_create(:user, email: @email) - @supporters = 2.times { force_create(:supporter, nonprofit: @nonprofit)} + @supporters = 2.times { force_create(:supporter, nonprofit: @nonprofit) } CHUNKED_UPLOADER.clear end - let(:export_header) { "Last Name,First Name,Just First Name,Full Name,Organization,Email,Phone,Address,City,State,Postal Code,Country,Supporter Id,Anonymous?,Total Contributed,Id,Last Payment Received,Notes,Tags".split(',')} + let(:export_header) { "Last Name,First Name,Just First Name,Full Name,Organization,Email,Phone,Address,City,State,Postal Code,Country,Supporter Id,Anonymous?,Total Contributed,Id,Last Payment Received,Notes,Tags".split(",") } - context '.initiate_export' do - context 'param verification' do - it 'performs initial verification' do + context ".initiate_export" do + context "param verification" do + it "performs initial verification" do expect { ExportSupporters.initiate_export(nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect(error.data.length).to eq(6) - expect_validation_errors(error.data, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_hash }]) + expect_validation_errors(error.data, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_hash}]) end) end - it 'nonprofit doesnt exist' do + it "nonprofit doesnt exist" do fake_npo = 8_888_881 expect { ExportSupporters.initiate_export(fake_npo, {}, 8_888_883) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -36,7 +36,7 @@ end) end - it 'user doesnt exist' do + it "user doesnt exist" do fake_user = 8_888_883 expect { ExportSupporters.initiate_export(@nonprofit.id, {}, fake_user) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) @@ -45,99 +45,97 @@ end end - it 'creates an export object and schedules job' do + it "creates an export object and schedules job" do Timecop.freeze(2020, 4, 5) do - stub_const("DelayedJobHelper", double('delayed')) - params = { param1: 'pp', root_url: 'https://localhost:8080' }.with_indifferent_access + stub_const("DelayedJobHelper", double("delayed")) + params = {param1: "pp", root_url: "https://localhost:8080"}.with_indifferent_access - expect(Export).to receive(:create).and_wrap_original {|m, *args| + expect(Export).to receive(:create).and_wrap_original { |m, *args| e = m.call(*args) # get original create - expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportSupporters, :run_export, [@nonprofit.id, params.to_json, @user.id, e.id]) #add the enqueue + expect(DelayedJobHelper).to receive(:enqueue_job).with(ExportSupporters, :run_export, [@nonprofit.id, params.to_json, @user.id, e.id]) # add the enqueue e } - ExportSupporters.initiate_export(@nonprofit.id, params, @user.id) export = Export.first - expected_export = { id: export.id, - user_id: @user.id, - nonprofit_id: @nonprofit.id, - status: 'queued', - export_type: 'ExportSupporters', - parameters: params.to_json, - updated_at: Time.now, - created_at: Time.now, - url: nil, - ended: nil, - exception: nil }.with_indifferent_access + expected_export = {id: export.id, + user_id: @user.id, + nonprofit_id: @nonprofit.id, + status: "queued", + export_type: "ExportSupporters", + parameters: params.to_json, + updated_at: Time.now, + created_at: Time.now, + url: nil, + ended: nil, + exception: nil}.with_indifferent_access expect(export.attributes).to eq(expected_export) end end end - context '.run_export' do - context 'param validation' do - it 'rejects basic invalid data' do + context ".run_export" do + context "param validation" do + it "rejects basic invalid data" do expect { ExportSupporters.run_export(nil, nil, nil, nil) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) - expect_validation_errors(error, [{ key: 'npo_id', name: :required }, - { key: 'npo_id', name: :is_integer }, - { key: 'user_id', name: :required }, - { key: 'user_id', name: :is_integer }, - { key: 'params', name: :required }, - { key: 'params', name: :is_json }, - { key: 'export_id', name: :required }, - { key: 'export_id', name: :is_integer }]) + expect_validation_errors(error, [{key: "npo_id", name: :required}, + {key: "npo_id", name: :is_integer}, + {key: "user_id", name: :required}, + {key: "user_id", name: :is_integer}, + {key: "params", name: :required}, + {key: "params", name: :is_json}, + {key: "export_id", name: :required}, + {key: "export_id", name: :is_integer}]) end) end - it 'rejects json which isnt a hash' do - expect { ExportSupporters.run_export(1, [{ item: '' }, { item: '' }].to_json, 1, 1) }.to(raise_error do |error| + it "rejects json which isnt a hash" do + expect { ExportSupporters.run_export(1, [{item: ""}, {item: ""}].to_json, 1, 1) }.to(raise_error do |error| expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error, [ - { key: :params, name: :is_hash } + {key: :params, name: :is_hash} ]) end) end - it 'no export throw an exception' do - expect { ExportSupporters.run_export(0, { x: 1 }.to_json, 0, 11_111) }.to(raise_error do |error| + it "no export throw an exception" do + expect { ExportSupporters.run_export(0, {x: 1}.to_json, 0, 11_111) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :export_id - expect(error.message).to start_with('Export') + expect(error.message).to start_with("Export") end) end - it 'no nonprofit' do + it "no nonprofit" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: @user) Timecop.freeze(2020, 4, 6) do - expect { ExportSupporters.run_export(0, { x: 1 }.to_json, @user.id, @export.id) }.to(raise_error do |error| + expect { ExportSupporters.run_export(0, {x: 1}.to_json, @user.id, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :npo_id - expect(error.message).to start_with('Nonprofit') + expect(error.message).to start_with("Nonprofit") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now - end) end end end - it 'no user' do + it "no user" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: @user) Timecop.freeze(2020, 4, 6) do - expect { ExportSupporters.run_export(@nonprofit.id, { x: 1 }.to_json, 0, @export.id) }.to(raise_error do |error| + expect { ExportSupporters.run_export(@nonprofit.id, {x: 1}.to_json, 0, @export.id) }.to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError expect(error.data[:key]).to eq :user_id - expect(error.message).to start_with('User') + expect(error.message).to start_with("User") @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now @@ -147,7 +145,7 @@ end end - it 'handles exception in upload properly' do + it "handles exception in upload properly" do Timecop.freeze(2020, 4, 5) do @export = force_create(:export, user: @user) # expect(ExportMailer.delay).to receive(:export_supporters_failed_notification) @@ -159,7 +157,7 @@ expect(error.message).to eq TestChunkedUploader::TEST_ERROR_MESSAGE @export.reload - expect(@export.status).to eq 'failed' + expect(@export.status).to eq "failed" expect(@export.exception).to eq error.to_s expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now @@ -170,31 +168,30 @@ end end - it 'uploads as expected' do + it "uploads as expected" do Timecop.freeze(2020, 4, 5) do @export = create(:export, user: @user, created_at: Time.now, updated_at: Time.now) - #expect_job_queued.with(JobTypes::ExportSupportersCompletedJob, @export) + # expect_job_queued.with(JobTypes::ExportSupportersCompletedJob, @export) Timecop.freeze(2020, 4, 6, 1, 2, 3) do - ExportSupporters.run_export(@nonprofit.id, {:root_url => "https://localhost:8080/"}.to_json, @user.id, @export.id) + ExportSupporters.run_export(@nonprofit.id, {root_url: "https://localhost:8080/"}.to_json, @user.id, @export.id) @export.reload expect(@export.url).to eq "http://fake.url/tmp/csv-exports/supporters-#{@export.id}-04-06-2020--01-02-03.csv" - expect(@export.status).to eq 'completed' + expect(@export.status).to eq "completed" expect(@export.exception).to be_nil expect(@export.ended).to eq Time.now expect(@export.updated_at).to eq Time.now csv = CSV.parse(TestChunkedUploader.output) - expect(csv.length).to eq (3) + expect(csv.length).to eq(3) expect(csv[0]).to eq export_header - expect(TestChunkedUploader.options[:content_type]).to eq 'text/csv' - expect(TestChunkedUploader.options[:content_disposition]).to eq 'attachment' + expect(TestChunkedUploader.options[:content_type]).to eq "text/csv" + expect(TestChunkedUploader.options[:content_disposition]).to eq "attachment" expect(@user).to have_received_email(subject: "Your supporters export is available!") end end end end - -end \ No newline at end of file +end diff --git a/spec/lib/fetch/fetch_misc_nonprofit_settings_spec.rb b/spec/lib/fetch/fetch_misc_nonprofit_settings_spec.rb index 92a0c639c..d7893ecef 100644 --- a/spec/lib/fetch/fetch_misc_nonprofit_settings_spec.rb +++ b/spec/lib/fetch/fetch_misc_nonprofit_settings_spec.rb @@ -1,39 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe FetchMiscellaneousNpInfo do - describe '.fetch' do - describe 'validates params' do - it 'with empty args' do - expect { FetchMiscellaneousNpInfo.fetch(nil) }.to(raise_error {|error| + describe ".fetch" do + describe "validates params" do + it "with empty args" do + expect { FetchMiscellaneousNpInfo.fetch(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :np_id, name: :required}, - {key: :np_id, name: :is_integer}]) - + {key: :np_id, name: :is_integer}]) }) end - it 'with invalid np' do - expect { FetchMiscellaneousNpInfo.fetch(50) }.to(raise_error {|error| + it "with invalid np" do + expect { FetchMiscellaneousNpInfo.fetch(50) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :np_id}]) }) end end - describe 'with valid nonprofit' do + describe "with valid nonprofit" do before(:each) do @np = force_create(:nonprofit) end - it 'returns hash with empty misc settings' do + it "returns hash with empty misc settings" do expect(FetchMiscellaneousNpInfo.fetch(@np.id).attributes).to eq(MiscellaneousNpInfo.new.attributes) end - it 'returns the misc if already there' do - a = force_create(:miscellaneous_np_info, :nonprofit => @np, :donate_again_url => 'http://donateagain.url') + it "returns the misc if already there" do + a = force_create(:miscellaneous_np_info, nonprofit: @np, donate_again_url: "http://donateagain.url") expect(FetchMiscellaneousNpInfo.fetch(@np.id)).to eq(a) end end end -end \ No newline at end of file +end diff --git a/spec/lib/fetch/fetch_nonprofit_email_spec.rb b/spec/lib/fetch/fetch_nonprofit_email_spec.rb index c481f90c1..eeddfb6dd 100644 --- a/spec/lib/fetch/fetch_nonprofit_email_spec.rb +++ b/spec/lib/fetch/fetch_nonprofit_email_spec.rb @@ -1,25 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe FetchNonprofitEmail, pending: true do + context ".with_charge" do + let(:charge) { Models::Charge } - context '.with_charge' do - let(:charge) { Models::Charge } + it "returns the nonprofit org email if it's there!" do + charge.nonprofit.email = "nonprofit@someorg.org" + expect(FetchNonprofitEmail.with_charge(charge)).to eq("nonprofit@someorg.org") + end - it "returns the nonprofit org email if it's there!" do - charge.nonprofit.email = 'nonprofit@someorg.org' - expect(FetchNonprofitEmail.with_charge(charge)).to eq('nonprofit@someorg.org') - end + it "returns support@commitchange.com if Nonprofit email is blank" do + charge.nonprofit.email = "" + expect(FetchNonprofitEmail.with_charge(charge)).to eq("support@commitchange.com") + end - it "returns support@commitchange.com if Nonprofit email is blank" do - charge.nonprofit.email = "" - expect(FetchNonprofitEmail.with_charge(charge)).to eq('support@commitchange.com') - end - - it "returns support@commitchange.com if Nonprofit email is nil" do - charge.nonprofit.email = nil - expect(FetchNonprofitEmail.with_charge(charge)).to eq('support@commitchange.com') - end - - end + it "returns support@commitchange.com if Nonprofit email is nil" do + charge.nonprofit.email = nil + expect(FetchNonprofitEmail.with_charge(charge)).to eq("support@commitchange.com") + end + end end diff --git a/spec/lib/format/csv_spec.rb b/spec/lib/format/csv_spec.rb index 17cd3825e..a5f5df8a1 100644 --- a/spec/lib/format/csv_spec.rb +++ b/spec/lib/format/csv_spec.rb @@ -1,36 +1,36 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Format::Csv do - describe '.from_data' do - def create_output - [ - { - email_address: 'email@email.com', name: "Eric Schultz" - }, - { - email_address: "penelope@email.com", name: "Penelope Schultz" - } - ] - end - context 'no titleize_header passed' do - it 'titleizes the header' do - result = Format::Csv.from_data(create_output) - expect(result).to eq "Email Address,Name\nemail@email.com,Eric Schultz\npenelope@email.com,Penelope Schultz\n" - end - end + describe ".from_data" do + def create_output + [ + { + email_address: "email@email.com", name: "Eric Schultz" + }, + { + email_address: "penelope@email.com", name: "Penelope Schultz" + } + ] + end + context "no titleize_header passed" do + it "titleizes the header" do + result = Format::Csv.from_data(create_output) + expect(result).to eq "Email Address,Name\nemail@email.com,Eric Schultz\npenelope@email.com,Penelope Schultz\n" + end + end - context 'false titleize_header passed' do - it 'titleizes the header' do - result = Format::Csv.from_data(create_output, titleize_header: false) - expect(result).to eq "email_address,name\nemail@email.com,Eric Schultz\npenelope@email.com,Penelope Schultz\n" - end - end + context "false titleize_header passed" do + it "titleizes the header" do + result = Format::Csv.from_data(create_output, titleize_header: false) + expect(result).to eq "email_address,name\nemail@email.com,Eric Schultz\npenelope@email.com,Penelope Schultz\n" + end + end - context 'true titleize_header passed' do - it 'titleizes the header' do - result = Format::Csv.from_data(create_output, titleize_header: true) - expect(result).to eq "Email Address,Name\nemail@email.com,Eric Schultz\npenelope@email.com,Penelope Schultz\n" - end - end - end + context "true titleize_header passed" do + it "titleizes the header" do + result = Format::Csv.from_data(create_output, titleize_header: true) + expect(result).to eq "Email Address,Name\nemail@email.com,Eric Schultz\npenelope@email.com,Penelope Schultz\n" + end + end + end end diff --git a/spec/lib/format/currency_spec.rb b/spec/lib/format/currency_spec.rb index 9675f0f20..a5975d272 100644 --- a/spec/lib/format/currency_spec.rb +++ b/spec/lib/format/currency_spec.rb @@ -1,48 +1,46 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Format::Currency do - symbol = Settings.intntl.currencies[0] + symbol = Settings.intntl.currencies[0] - describe '.dollars_to_cents' do - context 'with dollar sign' do - it 'converts to a cents value as an integer' do - expect(Format::Currency.dollars_to_cents("#{symbol}11.11")).to eq(1111) - end - end - - context 'without dollar sign' do - it 'converts to a cents value as an integer' do - expect(Format::Currency.dollars_to_cents("11.00")).to eq(1100) - end + describe ".dollars_to_cents" do + context "with dollar sign" do + it "converts to a cents value as an integer" do + expect(Format::Currency.dollars_to_cents("#{symbol}11.11")).to eq(1111) + end end - context 'with large amount' do - it 'converts to a cents value as an integer' do - expect(Format::Currency.dollars_to_cents("#{symbol}111111111111.11")).to eq(11111111111111) - end - end - end - - describe '.cents_to_dollars' do + context "without dollar sign" do + it "converts to a cents value as an integer" do + expect(Format::Currency.dollars_to_cents("11.00")).to eq(1100) + end + end - context 'hundreth-precision (eg $1.11)' do - it 'converts to dollars with hundredth precision' do - expect(Format::Currency.cents_to_dollars(111)).to eq("1.11") - end - end + context "with large amount" do + it "converts to a cents value as an integer" do + expect(Format::Currency.dollars_to_cents("#{symbol}111111111111.11")).to eq(11111111111111) + end + end + end - context 'tenth-precision (eg. $1.10)' do - it 'converts to dollars with a trailing zero' do - expect(Format::Currency.cents_to_dollars(110)).to eq("1.10") - end - end + describe ".cents_to_dollars" do + context "hundreth-precision (eg $1.11)" do + it "converts to dollars with hundredth precision" do + expect(Format::Currency.cents_to_dollars(111)).to eq("1.11") + end + end - context 'whole value (eg. $1)' do - it 'converts to dollars without decimals' do - expect(Format::Currency.cents_to_dollars(100)).to eq("1") - end - end + context "tenth-precision (eg. $1.10)" do + it "converts to dollars with a trailing zero" do + expect(Format::Currency.cents_to_dollars(110)).to eq("1.10") + end + end - end + context "whole value (eg. $1)" do + it "converts to dollars without decimals" do + expect(Format::Currency.cents_to_dollars(100)).to eq("1") + end + end + end end diff --git a/spec/lib/format/dedication_spec.rb b/spec/lib/format/dedication_spec.rb index 3e70fd2e0..cc2c6d0b0 100644 --- a/spec/lib/format/dedication_spec.rb +++ b/spec/lib/format/dedication_spec.rb @@ -1,16 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Format::Dedication do - - describe '.from_json' do - it 'returns string if not json' do + describe ".from_json" do + it "returns string if not json" do expect(Format::Dedication.from_json("Hello there")).to eq("Hello there") end - it 'returns dedication with type, name, and note if json' do + it "returns dedication with type, name, and note if json" do json = '{"type": "memory", "name": "Bob Ross", "note": "This is the note"}' expect(Format::Dedication.from_json(json)).to eq("Donation made in memory of Bob Ross. Note: This is the note") end - end + end end - diff --git a/spec/lib/format/geography_spec.rb b/spec/lib/format/geography_spec.rb index e439620f3..b62c5c111 100644 --- a/spec/lib/format/geography_spec.rb +++ b/spec/lib/format/geography_spec.rb @@ -1,20 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -describe Format::Geography do +describe Format::Geography do + describe ".full_state_to_code" do + it "converts a full state name, case-insensitive, to a state code" do + expect(Format::Geography.full_state_to_code("New mexico")).to eq("NM") + end - describe '.full_state_to_code' do + it "ignores pre-existing state codes" do + expect(Format::Geography.full_state_to_code("NM")).to eq("NM") + end - it 'converts a full state name, case-insensitive, to a state code' do - expect(Format::Geography.full_state_to_code('New mexico')).to eq('NM') - end - - it 'ignores pre-existing state codes' do - expect(Format::Geography.full_state_to_code('NM')).to eq('NM') - end - - it 'returns nil when unrecognized' do - expect(Format::Geography.full_state_to_code('xxyyxx')).to eq(nil) - end - end + it "returns nil when unrecognized" do + expect(Format::Geography.full_state_to_code("xxyyxx")).to eq(nil) + end + end end diff --git a/spec/lib/format/indefinitize_spec.rb b/spec/lib/format/indefinitize_spec.rb index d416920be..fb434d79a 100644 --- a/spec/lib/format/indefinitize_spec.rb +++ b/spec/lib/format/indefinitize_spec.rb @@ -1,23 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require_relative '../../../app/legacy_lib/format/indefinitize' +require_relative "../../../app/legacy_lib/format/indefinitize" describe Format::Indefinitize do - describe '#article' do + describe "#article" do it "returns an for string starting with vowel" do - expect(Format::Indefinitize.article('apple')).to eq('an') + expect(Format::Indefinitize.article("apple")).to eq("an") end it "returns a for string not starting with vowel" do - expect(Format::Indefinitize.article('bear')).to eq('a') + expect(Format::Indefinitize.article("bear")).to eq("a") end end - describe '#with_article' do + describe "#with_article" do it "returns an and word for string starting with vowel" do - expect(Format::Indefinitize.with_article('apple')).to eq('an apple') + expect(Format::Indefinitize.with_article("apple")).to eq("an apple") end it "returns a and word for not string starting with vowel" do - expect(Format::Indefinitize.with_article('bear')).to eq('a bear') + expect(Format::Indefinitize.with_article("bear")).to eq("a bear") end end end diff --git a/spec/lib/format/name_spec.rb b/spec/lib/format/name_spec.rb index be3c9980d..a60f06078 100644 --- a/spec/lib/format/name_spec.rb +++ b/spec/lib/format/name_spec.rb @@ -1,11 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Format::Name do - - describe '.email_from_np' do - - it 'gives the name, minus commas, with our email in brackets' do + describe ".email_from_np" do + it "gives the name, minus commas, with our email in brackets" do result = Format::Name.email_from_np("Test, X, Y") expect(result).to eq("\"Test X Y\" ") end diff --git a/spec/lib/format/url_spec.rb b/spec/lib/format/url_spec.rb index c8144bb87..5f733b584 100644 --- a/spec/lib/format/url_spec.rb +++ b/spec/lib/format/url_spec.rb @@ -1,15 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require_relative '../../../app/legacy_lib/format/url' +require_relative "../../../app/legacy_lib/format/url" describe Format::Url do + describe ".concat" do + let(:event_url) { "al/birmingham/hand-in-paw/events/picasso-pets" } + let(:root_url) { "http://localhost:8080/" } + let(:formatted_url) { "http://localhost:8080/al/birmingham/hand-in-paw/events/picasso-pets" } - describe '.concat' do - let(:event_url) {"al/birmingham/hand-in-paw/events/picasso-pets"} - let(:root_url) {"http://localhost:8080/"} - let(:formatted_url) {"http://localhost:8080/al/birmingham/hand-in-paw/events/picasso-pets"} - - it "removes extra whacks from the url" do - # and helps prevent broken links in emails - expect(Format::Url.concat(root_url, event_url)).to eq(formatted_url) - end - end + it "removes extra whacks from the url" do + # and helps prevent broken links in emails + expect(Format::Url.concat(root_url, event_url)).to eq(formatted_url) + end + end end diff --git a/spec/lib/hash_spec.rb b/spec/lib/hash_spec.rb index 2d07616b3..fa8d7b406 100644 --- a/spec/lib/hash_spec.rb +++ b/spec/lib/hash_spec.rb @@ -1,12 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require_relative '../../app/legacy_lib/hash' +require_relative "../../app/legacy_lib/hash" describe Hash do - describe '::with_defaults_unless_nil' do - + describe "::with_defaults_unless_nil" do subject { - Hash.with_defaults_unless_nil({new_key: 'good', key_with_nil_default: nil}) + Hash.with_defaults_unless_nil({new_key: "good", key_with_nil_default: nil}) } - it {is_expected.to eq({new_key: 'good'})} + it { is_expected.to eq({new_key: "good"}) } end end diff --git a/spec/lib/import/import_civicrm_payments_spec.rb b/spec/lib/import/import_civicrm_payments_spec.rb index ab21be8e9..2be419c51 100644 --- a/spec/lib/import/import_civicrm_payments_spec.rb +++ b/spec/lib/import/import_civicrm_payments_spec.rb @@ -1,9 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe ImportCivicrmPayments do - it 'is untested', pending: true do - pending 'add tests here' + it "is untested", pending: true do + pending "add tests here" fail end -end \ No newline at end of file +end diff --git a/spec/lib/insert/insert_bank_account_spec.rb b/spec/lib/insert/insert_bank_account_spec.rb index 45128374b..6a22f55d9 100644 --- a/spec/lib/insert/insert_bank_account_spec.rb +++ b/spec/lib/insert/insert_bank_account_spec.rb @@ -1,53 +1,49 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertBankAccount do - around(:each) do |example| - Timecop.freeze(2020,5,4) do + Timecop.freeze(2020, 5, 4) do StripeMockHelper.mock do example.run end end - end - let(:nonprofit) {force_create(:nonprofit) } - let(:user) { force_create(:user, :email => 'x@example.com')} + let(:nonprofit) { force_create(:nonprofit) } + let(:user) { force_create(:user, email: "x@example.com") } - - describe '.with_stripe' do - describe 'param validation' do - it 'validates np and user' do - expect { InsertBankAccount.with_stripe(nil, nil, nil)}.to(raise_error{|error| + describe ".with_stripe" do + describe "param validation" do + it "validates np and user" do + expect { InsertBankAccount.with_stripe(nil, nil, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [{:key => :nonprofit, :name => :required}, - {:key => :nonprofit, :name => :is_a}, - {:key => :user, :name => :required}, - {:key => :user, :name => :is_a}]) - + expect_validation_errors(error.data, [{key: :nonprofit, name: :required}, + {key: :nonprofit, name: :is_a}, + {key: :user, name: :required}, + {key: :user, name: :is_a}]) }) - expect { InsertBankAccount.with_stripe(1, 2, nil)}.to(raise_error{|error| + expect { InsertBankAccount.with_stripe(1, 2, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {:key => :nonprofit, :name => :is_a}, - {:key => :user, :name => :is_a}]) - + {key: :nonprofit, name: :is_a}, + {key: :user, name: :is_a} + ]) }) end - it 'validate stripe_bank_account_token' do - expect { InsertBankAccount.with_stripe(nonprofit, user, nil)}.to(raise_error{|error| + it "validate stripe_bank_account_token" do + expect { InsertBankAccount.with_stripe(nonprofit, user, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{ - :key => :stripe_bank_account_token, - :name => :required - }, - { - :key => :stripe_bank_account_token, - :name => :not_blank - }]) + key: :stripe_bank_account_token, + name: :required + }, + { + key: :stripe_bank_account_token, + name: :not_blank + }]) }) end @@ -57,59 +53,60 @@ # expect(error.message).to include("vetted") # }) # end - end - describe 'exceptions in main function' do + describe "exceptions in main function" do # before (:each) { nonprofit.vetted = true} - it 'StripeAccountUtils.find_or_create fails' do + it "StripeAccountUtils.find_or_create fails" do expect(StripeAccountUtils).to receive(:find_or_create).and_raise(StandardError.new) - expect { InsertBankAccount.with_stripe(nonprofit, user, {:stripe_bank_account_token => 'blah'})}.to(raise_error{|error| + expect { InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: "blah"}) }.to(raise_error { |error| expect(error).to be_a StandardError }) end - it 'Stripe::Account.retrieve fails' do + it "Stripe::Account.retrieve fails" do expect(StripeAccountUtils).to receive(:find_or_create).and_return("account_id") - StripeMockHelper.prepare_error(Stripe::StripeError.new("some error happened"), :get_account ) + StripeMockHelper.prepare_error(Stripe::StripeError.new("some error happened"), :get_account) - expect { InsertBankAccount.with_stripe(nonprofit, user, {:stripe_bank_account_token => 'blah'})}.to(raise_error{|error| + expect { InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: "blah"}) }.to(raise_error { |error| expect(error).to be_a Stripe::StripeError }) end end - describe 'works with account retrieval' do - before (:each) { nonprofit.vetted = true; nonprofit.save!} - let(:stripe_acct) {Stripe::Account.create(managed: true, country: 'US', display_name: "test_display_name")} + describe "works with account retrieval" do + before(:each) { + nonprofit.vetted = true + nonprofit.save! + } + let(:stripe_acct) { Stripe::Account.create(managed: true, country: "US", display_name: "test_display_name") } let(:stripe_bank_account_token) { StripeMockHelper.generate_bank_token(country: "US", routing_number: "110000000", account_number: "000123456789") } - it 'sets failure message when external_account create fails' do + it "sets failure message when external_account create fails" do expect(Stripe::Account).to receive(:retrieve).and_return(stripe_acct) StripeMockHelper.prepare_error(Stripe::StripeError.new("hmm"), :create_external_account) - expect { InsertBankAccount.with_stripe(nonprofit, user, {:stripe_bank_account_token => stripe_bank_account_token}) }.to raise_error {|error| + expect { InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: stripe_bank_account_token}) }.to raise_error { |error| expect(error).to be_a ArgumentError - expect(error.message).to eq 'Failed to connect the bank account: #' + expect(error.message).to eq "Failed to connect the bank account: #" } end - it 'works with external account creation' do + it "works with external account creation" do expect(Stripe::Account).to receive(:retrieve).and_return(stripe_acct) - result = InsertBankAccount.with_stripe(nonprofit, user, {:stripe_bank_account_token => stripe_bank_account_token}) - expected = {:email => user.email, - :stripe_bank_account_token => stripe_bank_account_token, - :pending_verification => true, - created_at: Time.now(), - updated_at: Time.now(), - status: nil, #doesn't seem to be used + result = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: stripe_bank_account_token}) + expected = {email: user.email, + stripe_bank_account_token: stripe_bank_account_token, + pending_verification: true, + created_at: Time.now, + updated_at: Time.now, + status: nil, # doesn't seem to be used id: 1, deleted: false, - account_number: nil, #doesn't seem to be used + account_number: nil, # doesn't seem to be used nonprofit_id: nonprofit.id, - bank_name: nil - }.with_indifferent_access + bank_name: nil}.with_indifferent_access expect(result.attributes.to_h.with_indifferent_access.except(:confirmation_token, :stripe_bank_account_id, :name)).to eq expected expect(result[:confirmation_token]).to_not be_blank expect(result[:stripe_bank_account_id]).to_not be_blank @@ -117,47 +114,45 @@ end end - describe 'handles replacing the old accounts' do - before (:each) { nonprofit.vetted = true; nonprofit.save! + describe "handles replacing the old accounts" do + before(:each) { + nonprofit.vetted = true + nonprofit.save! old_bank_account_false old_bank_account_nil old_bank_account_true } - let(:stripe_acct) {Stripe::Account.create(managed: true, country: 'US', display_name: "test_display_name")} + let(:stripe_acct) { Stripe::Account.create(managed: true, country: "US", display_name: "test_display_name") } let(:stripe_bank_account_token) { StripeMockHelper.generate_bank_token(country: "US", routing_number: "110000000", account_number: "000123456789") } - let(:old_bank_account_nil) { force_create(:bank_account, nonprofit: nonprofit, deleted: false)} - let(:old_bank_account_false) { force_create(:bank_account, nonprofit: nonprofit, deleted: false)} - let(:old_bank_account_true) { force_create(:bank_account, nonprofit: nonprofit, deleted: true)} - + let(:old_bank_account_nil) { force_create(:bank_account, nonprofit: nonprofit, deleted: false) } + let(:old_bank_account_false) { force_create(:bank_account, nonprofit: nonprofit, deleted: false) } + let(:old_bank_account_true) { force_create(:bank_account, nonprofit: nonprofit, deleted: true) } - - it 'works with external account creation' do + it "works with external account creation" do expect(Stripe::Account).to receive(:retrieve).and_return(stripe_acct) - result = InsertBankAccount.with_stripe(nonprofit, user, {:stripe_bank_account_token => stripe_bank_account_token}) - expected = {:email => user.email, - :stripe_bank_account_token => stripe_bank_account_token, - :pending_verification => true, - created_at: Time.now(), - updated_at: Time.now(), - status: nil, #doesn't seem to be used - id: result['id'], + result = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: stripe_bank_account_token}) + expected = {email: user.email, + stripe_bank_account_token: stripe_bank_account_token, + pending_verification: true, + created_at: Time.now, + updated_at: Time.now, + status: nil, # doesn't seem to be used + id: result["id"], deleted: false, - account_number: nil, #doesn't seem to be used + account_number: nil, # doesn't seem to be used nonprofit_id: nonprofit.id, - bank_name: nil - }.with_indifferent_access + bank_name: nil}.with_indifferent_access expect(result.attributes.with_indifferent_access.except(:confirmation_token, :stripe_bank_account_id, :name)).to eq expected expect(result[:confirmation_token]).to_not be_blank expect(result[:stripe_bank_account_id]).to_not be_blank expect(result[:name]).to_not be_blank - expect(nonprofit.bank_account).to eq result - expect(BankAccount.where('nonprofit_id = ?', nonprofit.id).count).to eq 4 - expect(BankAccount.where('nonprofit_id = ? and deleted = true', nonprofit.id).count).to eq 3 + expect(BankAccount.where("nonprofit_id = ?", nonprofit.id).count).to eq 4 + expect(BankAccount.where("nonprofit_id = ? and deleted = true", nonprofit.id).count).to eq 3 end end end -end \ No newline at end of file +end diff --git a/spec/lib/insert/insert_card_spec.rb b/spec/lib/insert/insert_card_spec.rb index c1ec92609..4159bc4ae 100644 --- a/spec/lib/insert/insert_card_spec.rb +++ b/spec/lib/insert/insert_card_spec.rb @@ -1,115 +1,110 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertCard do - describe'.with_stripe' do - - - let(:stripe_card_token) { StripeMockHelper.generate_card_token(last4: '9191', exp_year:2011)} - let(:default_card_attribs) { - { - created_at: Time.now, - updated_at: Time.now, - profile_id: nil, - status: nil, - inactive: nil, - deleted: false, - expiration_month: nil, - expiration_year: nil, - email:nil, - supporter_id: nil, - country: nil + describe ".with_stripe" do + let(:stripe_card_token) { StripeMockHelper.generate_card_token(last4: "9191", exp_year: 2011) } + let(:default_card_attribs) { + { + created_at: Time.now, + updated_at: Time.now, + profile_id: nil, + status: nil, + inactive: nil, + deleted: false, + expiration_month: nil, + expiration_year: nil, + email: nil, + supporter_id: nil, + country: nil + } } - } - - let(:nonprofit) { force_create(:nonprofit)} - let(:user) { user = force_create(:user) - force_create(:role, name: :nonprofit_admin, host: nonprofit, user: user) - user - } + let(:nonprofit) { force_create(:nonprofit) } + let(:user) { + user = force_create(:user) + force_create(:role, name: :nonprofit_admin, host: nonprofit, user: user) + user + } - around(:each) {|example| - Timecop.freeze(2020, 5, 4) do - StripeMockHelper.mock do - example.run + around(:each) { |example| + Timecop.freeze(2020, 5, 4) do + StripeMockHelper.mock do + example.run + end end - end - } - - it 'params are invalid' do - ret = InsertCard::with_stripe({ }) - expect(ret[:status]).to eq(:unprocessable_entity) - expect(ret[:json][:error]).to start_with('Validation error') - expect(ret[:json][:errors].length).to be(9) - - expect_validation_errors(ret[:json][:errors], [ {key: 'holder_id', name: :required}, - {key: 'holder_type', name: 'included_in'}, - {key: 'holder_type', name: 'required'}, - {key: 'stripe_card_id', name: 'required'}, - {key: 'stripe_card_id', name: 'not_blank'}, - {key: 'stripe_card_token', name: 'required'}, - {key: 'stripe_card_token', name: 'not_blank'}, - {key: 'name', name: 'required'}, - {key: 'name', name: 'not_blank'} - ]) - - end - - describe 'for nonprofits' do - + } - - - let(:supporter) { nonprofit.supporters.first } - it 'nonprofit doesn\'t exist' do - ret = InsertCard::with_stripe({:holder_id => 3, :holder_type => 'Nonprofit', :stripe_card_id => 'card_fafjeht', :stripe_card_token => stripe_card_token, :name => 'name'}) + it "params are invalid" do + ret = InsertCard.with_stripe({}) expect(ret[:status]).to eq(:unprocessable_entity) - expect(ret[:json][:error]).to include("Sorry, you need to provide a nonprofit or supporter") + expect(ret[:json][:error]).to start_with("Validation error") + expect(ret[:json][:errors].length).to be(9) + + expect_validation_errors(ret[:json][:errors], [{key: "holder_id", name: :required}, + {key: "holder_type", name: "included_in"}, + {key: "holder_type", name: "required"}, + {key: "stripe_card_id", name: "required"}, + {key: "stripe_card_id", name: "not_blank"}, + {key: "stripe_card_token", name: "required"}, + {key: "stripe_card_token", name: "not_blank"}, + {key: "name", name: "required"}, + {key: "name", name: "not_blank"}]) end - it 'should properly add nonprofit card when no card exists' do - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - orig_card = nonprofit.active_card - expect(orig_card).to be_nil - card_ret = InsertCard::with_stripe(card_data); - nonprofit.reload - card = nonprofit.active_card + describe "for nonprofits" do + let(:supporter) { nonprofit.supporters.first } + it "nonprofit doesn't exist" do + ret = InsertCard.with_stripe({holder_id: 3, holder_type: "Nonprofit", stripe_card_id: "card_fafjeht", stripe_card_token: stripe_card_token, name: "name"}) + expect(ret[:status]).to eq(:unprocessable_entity) + expect(ret[:json][:error]).to include("Sorry, you need to provide a nonprofit or supporter") + end - compare_card_returned_to_real(card_ret, card) + it "should properly add nonprofit card when no card exists" do + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + card_data = {holder_type: "Nonprofit", holder_id: nonprofit.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} + orig_card = nonprofit.active_card + expect(orig_card).to be_nil + card_ret = InsertCard.with_stripe(card_data) + nonprofit.reload + card = nonprofit.active_card + + compare_card_returned_to_real(card_ret, card) - expected_card = { + expected_card = { id: card.id, - name: 'card_name', + name: "card_name", stripe_card_token: stripe_card_token, - stripe_card_id: 'card_88888', - holder_type: 'Nonprofit', + stripe_card_id: "card_88888", + holder_type: "Nonprofit", holder_id: nonprofit.id, - stripe_customer_id: stripe_customer['id'] - }.merge(default_card_attribs).with_indifferent_access - - expect(card.attributes).to eq expected_card - - + stripe_customer_id: stripe_customer["id"] + }.merge(default_card_attribs).with_indifferent_access - expect(Card.where('holder_id = ? and holder_type = ?', nonprofit.id, 'Nonprofit').count).to eq(1) + expect(card.attributes).to eq expected_card - customer = verify_cust_added_np(card.stripe_customer_id, nonprofit.id) - expect(customer.sources.count).to eq(1) - expect(customer.sources.data[0].object).to eq('card') - expect(customer.sources.data[0].last4).to eq('9191') - expect(customer.sources.data[0].exp_year).to eq(2011) - end + expect(Card.where("holder_id = ? and holder_type = ?", nonprofit.id, "Nonprofit").count).to eq(1) - it 'invalid params get ignored' do + customer = verify_cust_added_np(card.stripe_customer_id, nonprofit.id) + expect(customer.sources.count).to eq(1) + expect(customer.sources.data[0].object).to eq("card") + expect(customer.sources.data[0].last4).to eq("9191") + expect(customer.sources.data[0].exp_year).to eq(2011) + end - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, - :name => "card_name", :created_at => DateTime.new(0), :updated_at => DateTime.new(0), :inactive => true} + it "invalid params get ignored" do + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + card_data = {holder_type: "Nonprofit", holder_id: nonprofit.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, + name: "card_name", created_at: DateTime.new(0), updated_at: DateTime.new(0), inactive: true} - card_ret = InsertCard::with_stripe(card_data); + card_ret = InsertCard.with_stripe(card_data) nonprofit.reload card = Card.find(card_ret[:json][:id]) @@ -117,39 +112,36 @@ expect(nonprofit.active_card).to eq card compare_card_returned_to_real(card_ret, card) - expected_card = { - id: card.id, - name: 'card_name', - stripe_card_token: stripe_card_token, - stripe_card_id: 'card_88888', - holder_type: 'Nonprofit', - holder_id: nonprofit.id, - stripe_customer_id: stripe_customer['id'] + id: card.id, + name: "card_name", + stripe_card_token: stripe_card_token, + stripe_card_id: "card_88888", + holder_type: "Nonprofit", + holder_id: nonprofit.id, + stripe_customer_id: stripe_customer["id"] }.merge(default_card_attribs).with_indifferent_access expect(card.attributes).to eq expected_card + end - end - - - describe 'card exists' do - before(:each) { - @first_card_tok = StripeMockHelper.generate_card_token(:last4 => '9999', :exp_year => '2122') - @stripe_customer = Stripe::Customer.create() - @stripe_customer.sources.create({token: @first_card_tok}) - - - } - - it 'should properly add nonprofit card and make old inactive' do - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - first_card = nonprofit.create_active_card(:stripe_card_id => 'fake mcfake', :stripe_card_token => @first_card_tok, :name=> 'fake name') + describe "card exists" do + before(:each) { + @first_card_tok = StripeMockHelper.generate_card_token(last4: "9999", exp_year: "2122") + @stripe_customer = Stripe::Customer.create + @stripe_customer.sources.create({token: @first_card_tok}) + } - card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - card_ret = InsertCard::with_stripe(card_data); + it "should properly add nonprofit card and make old inactive" do + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + first_card = nonprofit.create_active_card(stripe_card_id: "fake mcfake", stripe_card_token: @first_card_tok, name: "fake name") + card_data = {holder_type: "Nonprofit", holder_id: nonprofit.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} + card_ret = InsertCard.with_stripe(card_data) nonprofit.reload card = nonprofit.active_card @@ -157,323 +149,319 @@ compare_card_returned_to_real(card_ret, card) expected_card = { - id: card.id, - name: 'card_name', - stripe_card_token: stripe_card_token, - stripe_card_id: 'card_88888', - holder_type: 'Nonprofit', - holder_id: nonprofit.id, - stripe_customer_id: stripe_customer['id'] + id: card.id, + name: "card_name", + stripe_card_token: stripe_card_token, + stripe_card_id: "card_88888", + holder_type: "Nonprofit", + holder_id: nonprofit.id, + stripe_customer_id: stripe_customer["id"] }.merge(default_card_attribs).with_indifferent_access expect(card.attributes).to eq expected_card - expect(Card.where('holder_id = ? and holder_type = ?', nonprofit.id, 'Nonprofit').count).to eq(2) - expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', nonprofit.id, 'Nonprofit', false).count).to eq(1) + expect(Card.where("holder_id = ? and holder_type = ?", nonprofit.id, "Nonprofit").count).to eq(2) + expect(Card.where("holder_id = ? and holder_type = ? and inactive != ?", nonprofit.id, "Nonprofit", false).count).to eq(1) customer = verify_cust_added_np(card.stripe_customer_id, nonprofit.id) expect(customer.sources.count).to eq(1) - expect(customer.sources.data.any?{|s| s.object == 'card' && s.last4 == '9191' && s.exp_year == 2011}).to eq(true) + expect(customer.sources.data.any? { |s| s.object == "card" && s.last4 == "9191" && s.exp_year == 2011 }).to eq(true) - #verify the original card didn't change - expect(nonprofit.cards.find(first_card.id).attributes.select{|k,_| k != 'inactive'}).to eq first_card.attributes.select{|k, _| k != 'inactive'} + # verify the original card didn't change + expect(nonprofit.cards.find(first_card.id).attributes.select { |k, _| k != "inactive" }).to eq first_card.attributes.select { |k, _| k != "inactive" } expect(nonprofit.cards.find(first_card.id).inactive).to eq true - + end end - end - - it 'handle card errors' do - StripeMockHelper.prepare_card_error(:card_error, :new_customer) - card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - card_ret = InsertCard::with_stripe(card_data); + it "handle card errors" do + StripeMockHelper.prepare_card_error(:card_error, :new_customer) + card_data = {holder_type: "Nonprofit", holder_id: nonprofit.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} - expect(card_ret[:status]).to be :unprocessable_entity - expect(card_ret[:json][:error]).to start_with('Oops!') - end - - it 'handle stripe errors' do - StripeMockHelper.prepare_error(Stripe::StripeError.new('generic stripe error'), :new_customer) - card_data = { :holder_type => 'Nonprofit', :holder_id => nonprofit.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - - card_ret = InsertCard::with_stripe(card_data); - - expect(card_ret[:status]).to eq :unprocessable_entity - expect(card_ret[:json][:error]).to start_with('Oops!') - end + card_ret = InsertCard.with_stripe(card_data) + expect(card_ret[:status]).to be :unprocessable_entity + expect(card_ret[:json][:error]).to start_with("Oops!") + end - def verify_cust_added_np(stripe_customer_id, holder_id) - verify_cust_added(stripe_customer_id, holder_id, 'Nonprofit') - end - + it "handle stripe errors" do + StripeMockHelper.prepare_error(Stripe::StripeError.new("generic stripe error"), :new_customer) + card_data = {holder_type: "Nonprofit", holder_id: nonprofit.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} - end + card_ret = InsertCard.with_stripe(card_data) - describe 'for supporter' do - let(:supporter) {force_create(:supporter, nonprofit: nonprofit)} - let(:event) { - force_create(:event, nonprofit: nonprofit, end_datetime: Time.now.since(1.day))} - let(:user_not_from_nonprofit) {force_create(:user)} - def verify_cust_added_supporter(stripe_customer_id, holder_id) - verify_cust_added(stripe_customer_id, holder_id, 'Supporter') - end + expect(card_ret[:status]).to eq :unprocessable_entity + expect(card_ret[:json][:error]).to start_with("Oops!") + end - def verify_supporter_source_token(source_token, card) - verify_source_token(source_token, card, 1, Time.now.since(20.minutes)) + def verify_cust_added_np(stripe_customer_id, holder_id) + verify_cust_added(stripe_customer_id, holder_id, "Nonprofit") + end end - def verify_event_source_token(source_token, card, event) - verify_source_token(source_token, card, 20, event.end_datetime.since(20.days), event) - end + describe "for supporter" do + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } + let(:event) { + force_create(:event, nonprofit: nonprofit, end_datetime: Time.now.since(1.day)) + } + let(:user_not_from_nonprofit) { force_create(:user) } + def verify_cust_added_supporter(stripe_customer_id, holder_id) + verify_cust_added(stripe_customer_id, holder_id, "Supporter") + end - context 'card exists' do + def verify_supporter_source_token(source_token, card) + verify_source_token(source_token, card, 1, Time.now.since(20.minutes)) + end - let(:supporter) {create(:supporter, :has_a_card, nonprofit:nonprofit)} + def verify_event_source_token(source_token, card, event) + verify_source_token(source_token, card, 20, event.end_datetime.since(20.days), event) + end + context "card exists" do + let(:supporter) { create(:supporter, :has_a_card, nonprofit: nonprofit) } - it 'should properly add supporter card' do - expect(supporter.cards.count).to eq(1) - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - orig_card = supporter.cards.first - card_ret = InsertCard::with_stripe(card_data); - supporter.reload - card = supporter.cards.where('cards.name = ?', 'card_name').first - compare_card_returned_to_real(card_ret, card, card_ret[:json]['token']) + it "should properly add supporter card" do + expect(supporter.cards.count).to eq(1) + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + card_data = {holder_type: "Supporter", holder_id: supporter.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} + orig_card = supporter.cards.first + card_ret = InsertCard.with_stripe(card_data) + supporter.reload + card = supporter.cards.where("cards.name = ?", "card_name").first + compare_card_returned_to_real(card_ret, card, card_ret[:json]["token"]) - expected_card = { - id: card.id, - name: 'card_name', - stripe_card_token: stripe_card_token, - stripe_card_id: 'card_88888', - holder_id: supporter.id, - holder_type: 'Supporter', - stripe_customer_id: stripe_customer['id'], - }.merge(default_card_attribs).with_indifferent_access + expected_card = { + id: card.id, + name: "card_name", + stripe_card_token: stripe_card_token, + stripe_card_id: "card_88888", + holder_id: supporter.id, + holder_type: "Supporter", + stripe_customer_id: stripe_customer["id"] + }.merge(default_card_attribs).with_indifferent_access - expect(card.attributes).to eq expected_card + expect(card.attributes).to eq expected_card - expect(supporter.cards.count).to eq(2) + expect(supporter.cards.count).to eq(2) - expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(2) - expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0) + expect(Card.where("holder_id = ? and holder_type = ?", supporter.id, "Supporter").count).to eq(2) + expect(Card.where("holder_id = ? and holder_type = ? and inactive != ?", supporter.id, "Supporter", false).count).to eq(0) - expect(supporter.cards.find(orig_card.id)).to eq(orig_card) + expect(supporter.cards.find(orig_card.id)).to eq(orig_card) - verify_cust_added_supporter(card.stripe_customer_id, supporter.id) + verify_cust_added_supporter(card.stripe_customer_id, supporter.id) - verify_supporter_source_token(card_ret[:json]['token'], card) - end + verify_supporter_source_token(card_ret[:json]["token"], card) + end - it 'should properly add card for event' do - expect(supporter.cards.count).to eq(1) - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - orig_card = supporter.cards.first - card_ret = InsertCard::with_stripe(card_data, nil, event.id, user); - supporter.reload - card = supporter.cards.where('cards.name = ?', 'card_name').first - compare_card_returned_to_real(card_ret, card, card_ret[:json]['token']) + it "should properly add card for event" do + expect(supporter.cards.count).to eq(1) + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + card_data = {holder_type: "Supporter", holder_id: supporter.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} + orig_card = supporter.cards.first + card_ret = InsertCard.with_stripe(card_data, nil, event.id, user) + supporter.reload + card = supporter.cards.where("cards.name = ?", "card_name").first + compare_card_returned_to_real(card_ret, card, card_ret[:json]["token"]) - expected_card = { + expected_card = { id: card.id, - name: 'card_name', + name: "card_name", stripe_card_token: stripe_card_token, - stripe_card_id: 'card_88888', + stripe_card_id: "card_88888", holder_id: supporter.id, - holder_type: 'Supporter', - stripe_customer_id: stripe_customer['id'], - }.merge(default_card_attribs).with_indifferent_access - - expect(card.attributes).to eq expected_card + holder_type: "Supporter", + stripe_customer_id: stripe_customer["id"] + }.merge(default_card_attribs).with_indifferent_access - expect(supporter.cards.count).to eq(2) + expect(card.attributes).to eq expected_card - expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(2) - expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0) + expect(supporter.cards.count).to eq(2) - expect(supporter.cards.find(orig_card.id)).to eq(orig_card) + expect(Card.where("holder_id = ? and holder_type = ?", supporter.id, "Supporter").count).to eq(2) + expect(Card.where("holder_id = ? and holder_type = ? and inactive != ?", supporter.id, "Supporter", false).count).to eq(0) - verify_cust_added_supporter(card.stripe_customer_id, supporter.id) + expect(supporter.cards.find(orig_card.id)).to eq(orig_card) + verify_cust_added_supporter(card.stripe_customer_id, supporter.id) - verify_event_source_token(card_ret[:json]['token'], card, event) + verify_event_source_token(card_ret[:json]["token"], card, event) + end end - end - - context 'card doesnt exist' do - - it 'invalid params get ignored' do + context "card doesnt exist" do + it "invalid params get ignored" do stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, - :name => "card_name", :created_at => DateTime.new(0), :updated_at => DateTime.new(0), :inactive => true} - - card_ret = InsertCard.with_stripe(card_data); + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + card_data = {holder_type: "Supporter", holder_id: supporter.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, + name: "card_name", created_at: DateTime.new(0), updated_at: DateTime.new(0), inactive: true} + card_ret = InsertCard.with_stripe(card_data) card = Card.find(card_ret[:json][:id]) supporter.reload - compare_card_returned_to_real(card_ret, card, card_ret[:json]['token']) - + compare_card_returned_to_real(card_ret, card, card_ret[:json]["token"]) expected_card = { - id: card.id, - holder_type: 'Supporter', - holder_id: supporter.id, - stripe_card_token: stripe_card_token, - name: 'card_name', - stripe_card_id: 'card_88888', - stripe_customer_id: stripe_customer['id'] - + id: card.id, + holder_type: "Supporter", + holder_id: supporter.id, + stripe_card_token: stripe_card_token, + name: "card_name", + stripe_card_id: "card_88888", + stripe_customer_id: stripe_customer["id"] }.merge(default_card_attribs).with_indifferent_access expect(card.attributes).to eq expected_card - verify_supporter_source_token(card_ret[:json]['token'], card) - - - end + verify_supporter_source_token(card_ret[:json]["token"], card) + end - it 'should properly add supporter card when no card exist' do - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} + it "should properly add supporter card when no card exist" do + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } - card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - card_ret = InsertCard::with_stripe(card_data); - supporter.reload - card = supporter.cards.where('cards.name = ?', 'card_name').first - compare_card_returned_to_real(card_ret, card, card_ret[:json]['token']) - expected_card = { + card_data = {holder_type: "Supporter", holder_id: supporter.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} + card_ret = InsertCard.with_stripe(card_data) + supporter.reload + card = supporter.cards.where("cards.name = ?", "card_name").first + compare_card_returned_to_real(card_ret, card, card_ret[:json]["token"]) + expected_card = { id: card.id, - name: 'card_name', - stripe_card_id: 'card_88888', + name: "card_name", + stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, - stripe_customer_id: stripe_customer['id'], - holder_type: 'Supporter', + stripe_customer_id: stripe_customer["id"], + holder_type: "Supporter", holder_id: supporter.id - }.merge(default_card_attribs).with_indifferent_access - - expect(card.attributes).to eq expected_card + }.merge(default_card_attribs).with_indifferent_access - expect(supporter.cards.count).to eq(1) + expect(card.attributes).to eq expected_card - expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(1) - expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0) - verify_cust_added_supporter(card.stripe_customer_id, supporter.id) + expect(supporter.cards.count).to eq(1) - verify_supporter_source_token(card_ret[:json]['token'], card) - end + expect(Card.where("holder_id = ? and holder_type = ?", supporter.id, "Supporter").count).to eq(1) + expect(Card.where("holder_id = ? and holder_type = ? and inactive != ?", supporter.id, "Supporter", false).count).to eq(0) + verify_cust_added_supporter(card.stripe_customer_id, supporter.id) - it 'should properly add card for event' do + verify_supporter_source_token(card_ret[:json]["token"], card) + end - stripe_customer = nil - expect(Stripe::Customer).to receive(:create).and_wrap_original{|m, *args| stripe_customer = m.call(*args); stripe_customer} - card_data = { :holder_type => 'Supporter', :holder_id => supporter.id, :stripe_card_id => 'card_88888', :stripe_card_token => stripe_card_token, :name => "card_name" } - card_ret = InsertCard::with_stripe(card_data, nil, event.id, user); - supporter.reload - card = supporter.cards.where('cards.name = ?', 'card_name').first - compare_card_returned_to_real(card_ret, card, card_ret[:json]['token']) + it "should properly add card for event" do + stripe_customer = nil + expect(Stripe::Customer).to receive(:create).and_wrap_original { |m, *args| + stripe_customer = m.call(*args) + stripe_customer + } + card_data = {holder_type: "Supporter", holder_id: supporter.id, stripe_card_id: "card_88888", stripe_card_token: stripe_card_token, name: "card_name"} + card_ret = InsertCard.with_stripe(card_data, nil, event.id, user) + supporter.reload + card = supporter.cards.where("cards.name = ?", "card_name").first + compare_card_returned_to_real(card_ret, card, card_ret[:json]["token"]) - expected_card = { + expected_card = { id: card.id, - name: 'card_name', + name: "card_name", stripe_card_token: stripe_card_token, - stripe_card_id: 'card_88888', + stripe_card_id: "card_88888", holder_id: supporter.id, - holder_type: 'Supporter', - stripe_customer_id: stripe_customer['id'], - }.merge(default_card_attribs).with_indifferent_access + holder_type: "Supporter", + stripe_customer_id: stripe_customer["id"] + }.merge(default_card_attribs).with_indifferent_access - expect(card.attributes).to eq expected_card + expect(card.attributes).to eq expected_card - expect(supporter.cards.count).to eq(1) + expect(supporter.cards.count).to eq(1) - expect(Card.where('holder_id = ? and holder_type = ?', supporter.id, 'Supporter').count).to eq(1) - expect(Card.where('holder_id = ? and holder_type = ? and inactive != ?', supporter.id, 'Supporter', false).count).to eq(0) + expect(Card.where("holder_id = ? and holder_type = ?", supporter.id, "Supporter").count).to eq(1) + expect(Card.where("holder_id = ? and holder_type = ? and inactive != ?", supporter.id, "Supporter", false).count).to eq(0) - verify_cust_added_supporter(card.stripe_customer_id, supporter.id) + verify_cust_added_supporter(card.stripe_customer_id, supporter.id) - verify_event_source_token(card_ret[:json]['token'], card, event) + verify_event_source_token(card_ret[:json]["token"], card, event) + end end - end - + it "should return proper error when no supporter exists" do + ret = InsertCard.with_stripe({holder_id: 5555555, holder_type: "Supporter", stripe_card_id: "card_fafjeht", stripe_card_token: stripe_card_token, name: "name"}) + expect(ret[:status]).to eq(:unprocessable_entity) + expect(ret[:json][:error]).to include("Sorry, you need to provide a nonprofit or supporter") + end - it 'should return proper error when no supporter exists' do - ret = InsertCard::with_stripe({:holder_id => 5555555, :holder_type => 'Supporter', :stripe_card_id => 'card_fafjeht', :stripe_card_token => stripe_card_token, :name => 'name'}) - expect(ret[:status]).to eq(:unprocessable_entity) - expect(ret[:json][:error]).to include("Sorry, you need to provide a nonprofit or supporter") - end - - it 'should return proper error when you try to add using an event with unauthorized user' do - ret = InsertCard::with_stripe({holder_id: supporter.id, holder_type: 'Supporter', stripe_card_id: 'card_fafjeht', stripe_card_token: stripe_card_token, name: 'name'}, nil, event.id, user_not_from_nonprofit) + it "should return proper error when you try to add using an event with unauthorized user" do + ret = InsertCard.with_stripe({holder_id: supporter.id, holder_type: "Supporter", stripe_card_id: "card_fafjeht", stripe_card_token: stripe_card_token, name: "name"}, nil, event.id, user_not_from_nonprofit) - expect(ret[:json][:error]).to eq "You're not authorized to perform that action" - expect(ret[:status]).to eq (:unauthorized) - end + expect(ret[:json][:error]).to eq "You're not authorized to perform that action" + expect(ret[:status]).to eq(:unauthorized) + end - it 'should return proper error when an invalid event_id is provided' do - ret = InsertCard.with_stripe({holder_id: supporter.id, holder_type: 'Supporter', stripe_card_id: 'card_fafjeht', stripe_card_token: stripe_card_token, name: 'name'}, nil, 55555, user_not_from_nonprofit) - expect(ret).to eq({ status: :unprocessable_entity, json: {error: 'Oops! There was an error: 55555 is not a valid event'}}) - end + it "should return proper error when an invalid event_id is provided" do + ret = InsertCard.with_stripe({holder_id: supporter.id, holder_type: "Supporter", stripe_card_id: "card_fafjeht", stripe_card_token: stripe_card_token, name: "name"}, nil, 55555, user_not_from_nonprofit) + expect(ret).to eq({status: :unprocessable_entity, json: {error: "Oops! There was an error: 55555 is not a valid event"}}) + end - it 'should return proper error when event doesnt match the supporters nonprofit' do - supporter2 = force_create(:supporter) - ret = InsertCard.with_stripe({holder_id: supporter2.id, holder_type: 'Supporter', stripe_card_id: 'card_fafjeht', stripe_card_token: stripe_card_token, name: 'name'}, nil, event.id, user_not_from_nonprofit) - expect(ret).to eq({ status: :unprocessable_entity, json: {error: "Oops! There was an error: Event #{event.id} is not for the same nonprofit as supporter #{supporter2.id}"}}) + it "should return proper error when event doesnt match the supporters nonprofit" do + supporter2 = force_create(:supporter) + ret = InsertCard.with_stripe({holder_id: supporter2.id, holder_type: "Supporter", stripe_card_id: "card_fafjeht", stripe_card_token: stripe_card_token, name: "name"}, nil, event.id, user_not_from_nonprofit) + expect(ret).to eq({status: :unprocessable_entity, json: {error: "Oops! There was an error: Event #{event.id} is not for the same nonprofit as supporter #{supporter2.id}"}}) + end end + def compare_card_returned_to_real(card_ret, db_card, token = nil) + expect(card_ret[:status]).to eq(:ok) - - end - def compare_card_returned_to_real(card_ret, db_card, token=nil) - expect(card_ret[:status]).to eq(:ok) - - expected_json = db_card.attributes - expected_json.merge!({'token' => token}) - if token - expect(token).to match(UUID::Regex) + expected_json = db_card.attributes + expected_json.merge!({"token" => token}) + if token + expect(token).to match(UUID::Regex) + end + expect(card_ret[:json]).to eq(expected_json) end - expect(card_ret[:json]).to eq(expected_json) - end - def verify_cust_added(stripe_customer_id, holder_id, holder_type) - customer = Stripe::Customer.retrieve(stripe_customer_id) - # does the customer exist? Was it set properly? Was the card set properly - expect(customer).to_not be_nil - expected_metadata = { + def verify_cust_added(stripe_customer_id, holder_id, holder_type) + customer = Stripe::Customer.retrieve(stripe_customer_id) + # does the customer exist? Was it set properly? Was the card set properly + expect(customer).to_not be_nil + expected_metadata = { holder_id: holder_id, holder_type: holder_type, cardholders_name: nil - } - - expect(customer.metadata.to_hash).to eq expected_metadata - customer - end + } - def verify_source_token(source_token, card, max_uses, expiration_time, event=nil) - tok = SourceToken.where('token = ?', source_token).first - expected = { - created_at: Time.now, - updated_at: Time.now, - tokenizable_id: card.id, - tokenizable_type: 'Card', - max_uses: max_uses, - total_uses: 0, - expiration: expiration_time, - event_id: event ? event.id : nil, - token: source_token - }.with_indifferent_access - - expect(tok.attributes).to eq expected - end + expect(customer.metadata.to_hash).to eq expected_metadata + customer + end + def verify_source_token(source_token, card, max_uses, expiration_time, event = nil) + tok = SourceToken.where("token = ?", source_token).first + expected = { + created_at: Time.now, + updated_at: Time.now, + tokenizable_id: card.id, + tokenizable_type: "Card", + max_uses: max_uses, + total_uses: 0, + expiration: expiration_time, + event_id: event ? event.id : nil, + token: source_token + }.with_indifferent_access + + expect(tok.attributes).to eq expected + end end end diff --git a/spec/lib/insert/insert_charge_spec.rb b/spec/lib/insert/insert_charge_spec.rb index 21f1a0576..e8449b1a9 100644 --- a/spec/lib/insert/insert_charge_spec.rb +++ b/spec/lib/insert/insert_charge_spec.rb @@ -1,164 +1,176 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'stripe_mock' +require "rails_helper" +require "stripe_mock" describe InsertCharge do include_context :shared_donation_charge_context - let!(:donation) {force_create(:donation, id: 555)} - describe '.with_stripe' do - before(:each){ + let!(:donation) { force_create(:donation, id: 555) } + describe ".with_stripe" do + before(:each) { Settings.payment_provider.stripe_connect = true } - describe 'param validation' do - it 'does basic validation' do - expect { InsertCharge.with_stripe(nil) }.to(raise_error {|error| + describe "param validation" do + it "does basic validation" do + expect { InsertCharge.with_stripe(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, - [ - {:key => :amount, :name => :required}, - {:key => :amount, :name => :is_integer}, - {:key => :amount, :name => :min}, - {:key => :nonprofit_id, :name => :required}, - {:key => :nonprofit_id, :name => :is_integer}, - {:key => :supporter_id, :name => :required}, - {:key => :supporter_id, :name => :is_integer}, - {:key => :card_id, :name => :required}, - {:key => :card_id, :name => :is_integer}, - {:key => :statement, :name => :required}, - {:key => :statement, :name => :not_blank} - ]) + [ + {key: :amount, name: :required}, + {key: :amount, name: :is_integer}, + {key: :amount, name: :min}, + {key: :nonprofit_id, name: :required}, + {key: :nonprofit_id, name: :is_integer}, + {key: :supporter_id, name: :required}, + {key: :supporter_id, name: :is_integer}, + {key: :card_id, name: :required}, + {key: :card_id, name: :is_integer}, + {key: :statement, name: :required}, + {key: :statement, name: :not_blank} + ]) }) end - it 'verify the amount minimum works' do - expect { InsertCharge.with_stripe({amount: -1}) }.to(raise_error {|error| + it "verify the amount minimum works" do + expect { InsertCharge.with_stripe({amount: -1}) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, - [ - {:key => :amount, :name => :min}, - {:key => :nonprofit_id, :name => :required}, - {:key => :nonprofit_id, :name => :is_integer}, - {:key => :supporter_id, :name => :required}, - {:key => :supporter_id, :name => :is_integer}, - {:key => :card_id, :name => :required}, - {:key => :card_id, :name => :is_integer}, - {:key => :statement, :name => :required}, - {:key => :statement, :name => :not_blank} - - ]) + [ + {key: :amount, name: :min}, + {key: :nonprofit_id, name: :required}, + {key: :nonprofit_id, name: :is_integer}, + {key: :supporter_id, name: :required}, + {key: :supporter_id, name: :is_integer}, + {key: :card_id, name: :required}, + {key: :card_id, name: :is_integer}, + {key: :statement, name: :required}, + {key: :statement, name: :not_blank} + + ]) }) end - it 'verify that we check for valid nonprofit' do - expect { InsertCharge.with_stripe({amount: 100, - :nonprofit_id => 5555, - :supporter_id => 5555, - :card_id => 5555, - :statement => 'our statement'}) }.to(raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, - [ - {:key => :nonprofit_id} - ]) - }) + it "verify that we check for valid nonprofit" do + expect { + InsertCharge.with_stripe({amount: 100, + nonprofit_id: 5555, + supporter_id: 5555, + card_id: 5555, + statement: "our statement"}) + }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, + [ + {key: :nonprofit_id} + ]) + }) end - it 'verify that we check for valid supporter' do - expect { InsertCharge.with_stripe({amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => 5555, - :card_id => 5555, - :statement => 'our statement'}) }.to(raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, - [ - {:key => :supporter_id} - ]) - }) + it "verify that we check for valid supporter" do + expect { + InsertCharge.with_stripe({amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: 5555, + card_id: 5555, + statement: "our statement"}) + }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, + [ + {key: :supporter_id} + ]) + }) end - it 'verify that we check for valid card' do - expect { InsertCharge.with_stripe({amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => supporter.id, - :card_id => 5555, - :statement => 'our statement'}) }.to(raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, - [ - {:key => :card_id} - ]) - }) + it "verify that we check for valid card" do + expect { + InsertCharge.with_stripe({amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + card_id: 5555, + statement: "our statement"}) + }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, + [ + {key: :card_id} + ]) + }) end - it 'verify that we check that the supporter belongs to the correct nonprofit' do - expect { InsertCharge.with_stripe({amount: 100, - :nonprofit_id => other_nonprofit.id, - :supporter_id => supporter.id, - :card_id => card.id, - :statement => 'our statement'}) }.to(raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect(error.message).to eq "#{supporter.id} does not belong to this nonprofit #{other_nonprofit.id}" - expect_validation_errors(error.data, - [ - {:key => :supporter_id} - ]) - }) + it "verify that we check that the supporter belongs to the correct nonprofit" do + expect { + InsertCharge.with_stripe({amount: 100, + nonprofit_id: other_nonprofit.id, + supporter_id: supporter.id, + card_id: card.id, + statement: "our statement"}) + }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect(error.message).to eq "#{supporter.id} does not belong to this nonprofit #{other_nonprofit.id}" + expect_validation_errors(error.data, + [ + {key: :supporter_id} + ]) + }) end - it 'verify that we check that the card belongs to the correct supporter' do - expect { InsertCharge.with_stripe({amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => supporter.id, - :card_id => card_for_other_supporter.id, - :statement => 'our statement'}) }.to(raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect(error.message).to eq "#{card_for_other_supporter.id} does not belong to this supporter #{supporter.id}" - expect_validation_errors(error.data, - [ - {:key => :card_id} - ]) - }) + it "verify that we check that the card belongs to the correct supporter" do + expect { + InsertCharge.with_stripe({amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + card_id: card_for_other_supporter.id, + statement: "our statement"}) + }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect(error.message).to eq "#{card_for_other_supporter.id} does not belong to this supporter #{supporter.id}" + expect_validation_errors(error.data, + [ + {key: :card_id} + ]) + }) end end - describe 'handle StripeAccountUtils Find and Create failure' do - before(:each){ + describe "handle StripeAccountUtils Find and Create failure" do + before(:each) { StripeMockHelper.prepare_error(Stripe::StripeError.new("chaos"), :new_account) } - it 'does it fail properly' do - expect{ InsertCharge.with_stripe(amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => supporter.id, - :card_id => card.id, - :statement => 'our statement') }.to( raise_error{|error| - expect(error).to be_a Stripe::StripeError - }) + it "does it fail properly" do + expect { + InsertCharge.with_stripe(amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + card_id: card.id, + statement: "our statement") + }.to(raise_error { |error| + expect(error).to be_a Stripe::StripeError + }) expect(Charge).to_not be_exists expect(Payment).to_not be_exists end end - describe 'charge when customer belongs to us' do - RSpec.shared_context :charge_when_customer_belongs_to_us do + describe "charge when customer belongs to us" do + RSpec.shared_context :charge_when_customer_belongs_to_us do let(:negative_fee_total) { fee_total * -1 } - let(:net_total) { 100 + negative_fee_total} - before(:each){ - nonprofit.stripe_account_id = Stripe::Account.create()['id'] + let(:net_total) { 100 + negative_fee_total } + before(:each) { + nonprofit.stripe_account_id = Stripe::Account.create["id"] nonprofit.save! - card.stripe_customer_id = 'some other id' - cust = Stripe::Customer.create() - card.stripe_customer_id = cust['id'] + card.stripe_customer_id = "some other id" + cust = Stripe::Customer.create + card.stripe_customer_id = cust["id"] source = Stripe::Customer.create_source(cust.id, {source: generate_card_token(card_brand, card_country)}) card.stripe_card_id = source.id card.save! - new_cust = Stripe::Customer.create() + new_cust = Stripe::Customer.create new_source = Stripe::Customer.create_source(new_cust.id, {source: generate_card_token(card_brand, card_country)}) - card_for_other_supporter.stripe_customer_id = new_cust['id'] + card_for_other_supporter.stripe_customer_id = new_cust["id"] card_for_other_supporter.stripe_card_id = new_source.id card_for_other_supporter.save! - #billing_subscription - # StripeMockHelper.prepare_error(Stripe::StripeError.new("chaos"), :get_customer) + # billing_subscription + # StripeMockHelper.prepare_error(Stripe::StripeError.new("chaos"), :get_customer) } def create_expected_charge_args(expected_card, fee_total) @@ -166,91 +178,83 @@ def create_expected_charge_args(expected_card, fee_total) application_fee_amount: fee_total, customer: expected_card.stripe_customer_id, amount: 100, - currency: 'usd', - description: 'our statement<> blah-no-way', - statement_descriptor_suffix: 'our statement blah-n', + currency: "usd", + description: "our statement<> blah-no-way", + statement_descriptor_suffix: "our statement blah-n", metadata: nil, - :transfer_data=>{:destination=>nonprofit.stripe_account_id}, - :on_behalf_of=> nonprofit.stripe_account_id + transfer_data: {destination: nonprofit.stripe_account_id}, + on_behalf_of: nonprofit.stripe_account_id }, { - :stripe_version=>"2019-09-09" + stripe_version: "2019-09-09" }] end - - it 'handles card error' do - expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card, fee_total)).and_wrap_original{|m, *args| m.call(*args)} + it "handles card error" do + expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card, fee_total)).and_wrap_original { |m, *args| m.call(*args) } StripeMockHelper.prepare_card_error(:card_declined) finished_result = InsertCharge.with_stripe(amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => supporter.id, - :card_id => card.id, - :statement => 'our statement<> blah-no-way') - - common_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id: nil, status: 'failed', failure_message: 'There was an error with your card: The card was declined', created_at: Time.now, updated_at: Time.now, disbursed: nil} + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + card_id: card.id, + statement: "our statement<> blah-no-way") + common_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id: nil, status: "failed", failure_message: "There was an error with your card: The card was declined", created_at: Time.now, updated_at: Time.now, disbursed: nil} result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access - expect(finished_result['charge'].attributes).to eq result_expected + expect(finished_result["charge"].attributes).to eq result_expected expect(Charge.first.attributes).to eq result_expected expect(Payment).to_not be_exists - - end - it 'handles general Stripe error' do - expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card, fee_total)).and_wrap_original{|m, *args| m.call(*args)} + it "handles general Stripe error" do + expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(card, fee_total)).and_wrap_original { |m, *args| m.call(*args) } StripeMockHelper.prepare_error(Stripe::StripeError.new("blah"), :new_charge) finished_result = InsertCharge.with_stripe(amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => supporter.id, - :card_id => card.id, - :statement => 'our statement<> blah-no-way') - - common_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id: nil, status: 'failed', failure_message: "We're sorry, but something went wrong. We've been notified about this issue.", created_at: Time.now, updated_at: Time.now, disbursed: nil} + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + card_id: card.id, + statement: "our statement<> blah-no-way") + common_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id: nil, status: "failed", failure_message: "We're sorry, but something went wrong. We've been notified about this issue.", created_at: Time.now, updated_at: Time.now, disbursed: nil} result_expected = common_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: nil, supporter_id: supporter.id, ticket_id: nil, payment_id: nil, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access - expect(finished_result['charge'].attributes).to eq result_expected + expect(finished_result["charge"].attributes).to eq result_expected expect(Charge.first.attributes).to eq result_expected expect(Payment).to_not be_exists - end - describe 'input success' do - let (:date) { Time.new(2002,10,31)} - + describe "input success" do + let(:date) { Time.new(2002, 10, 31) } - it 'saves the payment and updates the charge' do + it "saves the payment and updates the charge" do saves_the_payment_updates_the_charge(card, fee_total) end - it 'saves the payment and updates the charge, if old rd and using wrong card' do - saves_the_payment_updates_the_charge(card_for_other_supporter, fee_total, true) + it "saves the payment and updates the charge, if old rd and using wrong card" do + saves_the_payment_updates_the_charge(card_for_other_supporter, fee_total, true) end - it 'saves the payment and updates the charge with passed date' do + it "saves the payment and updates the charge with passed date" do saves_the_payment_and_updates_the_charge_with_passed_date(card, fee_total) end - it 'saves the payment and updates the charge with passed date, if old rd and using wrong card' do + it "saves the payment and updates the charge with passed date, if old rd and using wrong card" do saves_the_payment_and_updates_the_charge_with_passed_date(card, fee_total, true) end - def insert_charge_input(expected_card, fee_total, pass_old_donation=nil, pass_date=nil) + def insert_charge_input(expected_card, fee_total, pass_old_donation = nil, pass_date = nil) inner = {amount: 100, - :nonprofit_id => nonprofit.id, - :supporter_id => supporter.id, - card_id: expected_card.id, - :donation_id => 555, - :towards => 'blah', - :kind => 'kind', - :statement => 'our statement<> blah-no-way', - } + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + card_id: expected_card.id, + donation_id: 555, + towards: "blah", + kind: "kind", + statement: "our statement<> blah-no-way"} if pass_old_donation inner = inner.merge(old_donation: true) @@ -263,136 +267,123 @@ def insert_charge_input(expected_card, fee_total, pass_old_donation=nil, pass_da inner end - def saves_the_payment_updates_the_charge(expected_card, fee_total, pass_old_donation=nil) - - stripe_charge_id = nil - expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card,fee_total)).and_wrap_original{|m, *args| a= m.call(*args); - stripe_charge_id = a['id'] - a} - - - finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, fee_total, pass_old_donation)) - - common_charge_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil} - - - result_charge_expected = common_charge_expected.merge({card_id: expected_card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access - - - expect(finished_result['charge'].attributes).to eq result_charge_expected - expect(Charge.first.attributes).to eq result_charge_expected - expect(Charge.count).to eq 1 - - - common_payment_expected = {id: Payment.first.id, - gross_amount: 100, - fee_total: negative_fee_total, - net_amount: net_total, - towards: 'blah', - kind: 'kind', - donation_id: 555, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - refund_total: 0, - date: Time.now, - created_at: Time.now, - updated_at: Time.now - }.with_indifferent_access - - expect(finished_result['payment'].attributes).to eq common_payment_expected - expect(Payment.first.attributes).to eq common_payment_expected - expect(Payment.count).to eq 1 - + def saves_the_payment_updates_the_charge(expected_card, fee_total, pass_old_donation = nil) + stripe_charge_id = nil + expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card, fee_total)).and_wrap_original { |m, *args| + a = m.call(*args) + stripe_charge_id = a["id"] + a + } + + finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, fee_total, pass_old_donation)) + + common_charge_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id: stripe_charge_id, status: "pending", failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil} + + result_charge_expected = common_charge_expected.merge({card_id: expected_card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access + + expect(finished_result["charge"].attributes).to eq result_charge_expected + expect(Charge.first.attributes).to eq result_charge_expected + expect(Charge.count).to eq 1 + + common_payment_expected = {id: Payment.first.id, + gross_amount: 100, + fee_total: negative_fee_total, + net_amount: net_total, + towards: "blah", + kind: "kind", + donation_id: 555, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + refund_total: 0, + date: Time.now, + created_at: Time.now, + updated_at: Time.now}.with_indifferent_access + + expect(finished_result["payment"].attributes).to eq common_payment_expected + expect(Payment.first.attributes).to eq common_payment_expected + expect(Payment.count).to eq 1 end - def saves_the_payment_and_updates_the_charge_with_passed_date(expected_card, fee_total, pass_old_donation=nil) - - stripe_charge_id = nil - expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card, fee_total )).and_wrap_original{|m, *args| a= m.call(*args); - stripe_charge_id = a['id'] - a} - - - finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, fee_total, pass_old_donation, true)) - - common_charge_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id:stripe_charge_id, status: 'pending', failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil} - - - result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access - - - expect(finished_result['charge'].attributes).to eq result_charge_expected - expect(Charge.first.attributes).to eq result_charge_expected - expect(Charge.count).to eq 1 - - - common_payment_expected = {id: Payment.first.id, - gross_amount: 100, - fee_total: negative_fee_total, - net_amount: net_total, - towards: 'blah', - kind: 'kind', - donation_id: 555, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - refund_total: 0, - date: date, - created_at: Time.now, - updated_at: Time.now - }.with_indifferent_access - - expect(finished_result['payment'].attributes).to eq common_payment_expected - expect(Payment.first.attributes).to eq common_payment_expected - expect(Payment.count).to eq 1 - + def saves_the_payment_and_updates_the_charge_with_passed_date(expected_card, fee_total, pass_old_donation = nil) + stripe_charge_id = nil + expect(Stripe::Charge).to receive(:create).with(*create_expected_charge_args(expected_card, fee_total)).and_wrap_original { |m, *args| + a = m.call(*args) + stripe_charge_id = a["id"] + a + } + + finished_result = InsertCharge.with_stripe(insert_charge_input(expected_card, fee_total, pass_old_donation, true)) + + common_charge_expected = {id: Charge.first.id, amount: 100, fee: fee_total, stripe_charge_id: stripe_charge_id, status: "pending", failure_message: nil, created_at: Time.now, updated_at: Time.now, disbursed: nil} + + result_charge_expected = common_charge_expected.merge({card_id: card.id, nonprofit_id: nonprofit.id, donation_id: 555, supporter_id: supporter.id, ticket_id: nil, payment_id: Payment.first.id, profile_id: nil, direct_debit_detail_id: nil}).with_indifferent_access + + expect(finished_result["charge"].attributes).to eq result_charge_expected + expect(Charge.first.attributes).to eq result_charge_expected + expect(Charge.count).to eq 1 + + common_payment_expected = {id: Payment.first.id, + gross_amount: 100, + fee_total: negative_fee_total, + net_amount: net_total, + towards: "blah", + kind: "kind", + donation_id: 555, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + refund_total: 0, + date: date, + created_at: Time.now, + updated_at: Time.now}.with_indifferent_access + + expect(finished_result["payment"].attributes).to eq common_payment_expected + expect(Payment.first.attributes).to eq common_payment_expected + expect(Payment.count).to eq 1 end end - end - - describe 'visa local' do - let(:card_brand) { "Visa"} - let(:card_country) { "US"} - let(:fee_total) { 36} + describe "visa local" do + let(:card_brand) { "Visa" } + let(:card_country) { "US" } + let(:fee_total) { 36 } include_context :charge_when_customer_belongs_to_us end - describe 'visa foreign' do - let(:card_brand) { "Visa"} - let(:card_country) { "UK"} - let(:fee_total) { 37} + describe "visa foreign" do + let(:card_brand) { "Visa" } + let(:card_country) { "UK" } + let(:fee_total) { 37 } include_context :charge_when_customer_belongs_to_us end - - describe 'amex local' do - let(:card_brand) { "American Express"} - let(:card_country) { "US"} - let(:fee_total) { 11} + + describe "amex local" do + let(:card_brand) { "American Express" } + let(:card_country) { "US" } + let(:fee_total) { 11 } include_context :charge_when_customer_belongs_to_us end - - describe 'amex foreign' do - let(:card_brand) { "American Express"} - let(:card_country) { "UK"} - let(:fee_total) { 12} + + describe "amex foreign" do + let(:card_brand) { "American Express" } + let(:card_country) { "UK" } + let(:fee_total) { 12 } include_context :charge_when_customer_belongs_to_us end - describe 'discover local' do - let(:card_brand) { "Discover"} - let(:card_country) { "US"} - let(:fee_total) {40} + describe "discover local" do + let(:card_brand) { "Discover" } + let(:card_country) { "US" } + let(:fee_total) { 40 } include_context :charge_when_customer_belongs_to_us end - describe 'discover foreign' do - let(:card_brand) { "Discover"} - let(:card_country) { "RU"} - let(:fee_total) {41} + describe "discover foreign" do + let(:card_brand) { "Discover" } + let(:card_country) { "RU" } + let(:fee_total) { 41 } include_context :charge_when_customer_belongs_to_us end - end - end + end end diff --git a/spec/lib/insert/insert_custom_field_joins_spec.rb b/spec/lib/insert/insert_custom_field_joins_spec.rb index 9294fa85a..b141f9408 100644 --- a/spec/lib/insert/insert_custom_field_joins_spec.rb +++ b/spec/lib/insert/insert_custom_field_joins_spec.rb @@ -1,50 +1,48 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - +require "rails_helper" describe InsertCustomFieldJoins do - describe '.find_or_create' do - let(:nonprofit) { force_create(:nonprofit)} - let(:other_nonprofit) { force_create(:nonprofit)} - let(:supporter) {force_create(:supporter, :nonprofit => nonprofit)} - let(:other_supporter){force_create(:supporter, :nonprofit => other_nonprofit)} + describe ".find_or_create" do + let(:nonprofit) { force_create(:nonprofit) } + let(:other_nonprofit) { force_create(:nonprofit) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } + let(:other_supporter) { force_create(:supporter, nonprofit: other_nonprofit) } - let(:initial_custom_field_master){ force_create(:custom_field_master, :nonprofit => nonprofit, :name => "CFM Name")} + let(:initial_custom_field_master) { force_create(:custom_field_master, nonprofit: nonprofit, name: "CFM Name") } - describe 'param validation' do - it 'basic validation' do - expect {InsertCustomFieldJoins.find_or_create(nil, nil, nil)}.to(raise_error {|error| + describe "param validation" do + it "basic validation" do + expect { InsertCustomFieldJoins.find_or_create(nil, nil, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {:key => :np_id, :name => :required}, - {:key => :np_id, :name => :is_integer}, - {:key => :supporter_ids, :name => :required}, - {:key => :supporter_ids, :name => :is_array}, - {:key => :supporter_ids, :name => :min_length}, - {:key => :field_data, :name => :required}, - {:key => :field_data, :name => :is_array}, - {:key => :field_data, :name => :min_length} + {key: :np_id, name: :required}, + {key: :np_id, name: :is_integer}, + {key: :supporter_ids, name: :required}, + {key: :supporter_ids, name: :is_array}, + {key: :supporter_ids, name: :min_length}, + {key: :field_data, name: :required}, + {key: :field_data, name: :is_array}, + {key: :field_data, name: :min_length} ]) - }) end - it 'validate nonprofit existence' do - expect {InsertCustomFieldJoins.find_or_create(5, [555], [[1, 1]])}.to(raise_error {|error| + it "validate nonprofit existence" do + expect { InsertCustomFieldJoins.find_or_create(5, [555], [[1, 1]]) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {:key => :np_id} + {key: :np_id} ]) expect(error.message).to eq "5 is not a valid non-profit" }) end - it 'validate supporter in nonprofit' do - expect {InsertCustomFieldJoins.find_or_create(nonprofit.id, [other_supporter.id], [[1, 1]])}.to(raise_error {|error| + it "validate supporter in nonprofit" do + expect { InsertCustomFieldJoins.find_or_create(nonprofit.id, [other_supporter.id], [[1, 1]]) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {:key => :supporter_ids} + {key: :supporter_ids} ]) expect(error.message).to eq "#{other_supporter.id} is not a valid supporter for nonprofit #{nonprofit.id}" @@ -52,147 +50,134 @@ end end - it 'run insert' do - - new_cf_name = 'new cf name' - new_cf_value = 'value' - old_cf_value = 'old_cf_value' + it "run insert" do + new_cf_name = "new cf name" + new_cf_value = "value" + old_cf_value = "old_cf_value" expect(InsertCustomFieldJoins).to receive(:in_bulk) do |np_id, supporters_id, field_data| expect(np_id).to eq nonprofit.id expect(supporters_id).to eq [supporter.id] expect(field_data.length).to eq 2 - expect(field_data).to include( { :custom_field_master_id => initial_custom_field_master.id, :value => old_cf_value}) - expect(field_data).to include( { :custom_field_master_id => CustomFieldMaster.where(:name => new_cf_name).first.id, :value => new_cf_value}) + expect(field_data).to include({custom_field_master_id: initial_custom_field_master.id, value: old_cf_value}) + expect(field_data).to include({custom_field_master_id: CustomFieldMaster.where(name: new_cf_name).first.id, value: new_cf_value}) end - result = InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [ - [ - initial_custom_field_master.name, - old_cf_value - ], - [ - new_cf_name, - new_cf_value - ]]) + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [ + [ + initial_custom_field_master.name, + old_cf_value + ], + [ + new_cf_name, + new_cf_value + ] + ]) expect(CustomFieldMaster.count).to eq 2 end - end - - describe '.in_bulk' do - context 'parameter validation' do - it 'should validate parameters' do - - response = InsertCustomFieldJoins::in_bulk(nil, nil, nil) + describe ".in_bulk" do + context "parameter validation" do + it "should validate parameters" do + response = InsertCustomFieldJoins.in_bulk(nil, nil, nil) errors = response[:json][:errors] expect(errors.length).to eq(6) - expect(response[:status]).to eq (:unprocessable_entity) + expect(response[:status]).to eq(:unprocessable_entity) expect_validation_errors(errors, [ - {key: :np_id, name: :required}, - {key: :np_id, name: :is_integer}, - {key: :supporter_ids, name: :required}, - {key: :supporter_ids, name: :is_array}, - {key: :field_data, name: :is_array}, - {key: :field_data, name: :required} + {key: :np_id, name: :required}, + {key: :np_id, name: :is_integer}, + {key: :supporter_ids, name: :required}, + {key: :supporter_ids, name: :is_array}, + {key: :field_data, name: :is_array}, + {key: :field_data, name: :required} ]) - end - context 'requiring db' do - + context "requiring db" do before(:each) { - @nonprofit = force_create(:nonprofit) - @bad_nonprofit = force_create(:nonprofit, :id => 50) + @nonprofit = force_create(:nonprofit) + @bad_nonprofit = force_create(:nonprofit, id: 50) } - it 'nonprofit must be valid' do - response = InsertCustomFieldJoins::in_bulk(124571590, [], []) - expect(response[:status]).to eq (:unprocessable_entity) - expect(response[:json][:error]).to include("Nonprofit #{124571590} is not valid") + it "nonprofit must be valid" do + response = InsertCustomFieldJoins.in_bulk(124571590, [], []) + expect(response[:status]).to eq(:unprocessable_entity) + expect(response[:json][:error]).to include("Nonprofit 124571590 is not valid") end - it 'supporters if empty should do nothing' do - response = InsertCustomFieldJoins::in_bulk(@nonprofit.id, [], []) + it "supporters if empty should do nothing" do + response = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [], []) expect(response).to eq(successful_json(0, 0)) end - it 'supporters if empty should do nothing' do - response = InsertCustomFieldJoins::in_bulk(@nonprofit.id, [50], []) + it "supporters if empty should do nothing" do + response = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [50], []) expect(response).to eq(successful_json(0, 0)) end - end - - end - context 'main testing' do + context "main testing" do before(:each) { @nonprofit = force_create(:nonprofit) @random_supporter = create(:supporter) @other_nonprofit = force_create(:nonprofit) - @delete_cfm= [20, 40, 60] + @delete_cfm = [20, 40, 60] @add_cfm = [25, 35] - @supporters = { - :np_supporter_with_add => { - :cfm_ids => [65, 75, 85] - }, - :np_supporter_with_cfms_to_delete => { - :cfm_ids => [40, 75, 85] - }, - - :np_supporter_with_no_changes => { - :cfm_ids => @add_cfm - }, - :np_supporter_with_some_of_both => { - - :cfm_ids => [20, 35] - }, - :supporter_from_other_np => { - :cfm_ids => [100, 150, 200], - :other_np => true - } + np_supporter_with_add: { + cfm_ids: [65, 75, 85] + }, + np_supporter_with_cfms_to_delete: { + cfm_ids: [40, 75, 85] + }, + + np_supporter_with_no_changes: { + cfm_ids: @add_cfm + }, + np_supporter_with_some_of_both: { + + cfm_ids: [20, 35] + }, + supporter_from_other_np: { + cfm_ids: [100, 150, 200], + other_np: true + } } - @supporters.each_key {|k| + @supporters.each_key { |k| i = @supporters[k] - nonprofit_for_supporter =i[:other_np] ? @other_nonprofit : @nonprofit - i[:entity] = create(:supporter, :nonprofit => nonprofit_for_supporter) - i[:cfm_ids].each {|j| - + nonprofit_for_supporter = i[:other_np] ? @other_nonprofit : @nonprofit + i[:entity] = create(:supporter, nonprofit: nonprofit_for_supporter) + i[:cfm_ids].each { |j| cfm = CustomFieldMaster.exists?(id: j) ? CustomFieldMaster.find(j) : create(:custom_field_master, id: j, nonprofit: nonprofit_for_supporter, name: "CFM #{j}") - create(:custom_field_join, :value_from_id, :supporter_id => i[:entity].id, :custom_field_master => cfm) + create(:custom_field_join, :value_from_id, supporter_id: i[:entity].id, custom_field_master: cfm) } } } - it 'invalid nonprofit-supporter combo returns okay' do - results = InsertCustomFieldJoins::in_bulk(@nonprofit.id, [@supporters[:supporter_from_other_np][:entity].id], []) + it "invalid nonprofit-supporter combo returns okay" do + results = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [@supporters[:supporter_from_other_np][:entity].id], []) expect(results).to eq(successful_json(0, 0)) end - - it 'strips cfms which dont belong to nonprofit' do - results = InsertCustomFieldJoins::in_bulk(@nonprofit.id, [@supporters[:np_supporter_with_add][:entity].id], - create_cfm_data([100], [150])) + it "strips cfms which dont belong to nonprofit" do + results = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [@supporters[:np_supporter_with_add][:entity].id], + create_cfm_data([100], [150])) expect(results).to eq(successful_json(0, 0)) - expect(CustomFieldJoin.where('supporter_id = ? and custom_field_master_id = ?', @supporters[:np_supporter_with_add][:entity].id, 100).count).to eq 0 - + expect(CustomFieldJoin.where("supporter_id = ? and custom_field_master_id = ?", @supporters[:np_supporter_with_add][:entity].id, 100).count).to eq 0 end - it 'delete' do - + it "delete" do expect(CustomFieldJoin.count).to eq 13 @supporters[:np_supporter_with_some_of_both][:entity].id - results = InsertCustomFieldJoins::in_bulk(@nonprofit.id, - [@supporters[:np_supporter_with_some_of_both][:entity].id, @supporters[:np_supporter_with_cfms_to_delete][:entity].id, @supporters[:np_supporter_with_add][:entity].id, @supporters[:supporter_from_other_np][:entity].id, @supporters[:np_supporter_with_no_changes][:entity].id], - create_cfm_data(@add_cfm, @delete_cfm)) + InsertCustomFieldJoins.in_bulk(@nonprofit.id, + [@supporters[:np_supporter_with_some_of_both][:entity].id, @supporters[:np_supporter_with_cfms_to_delete][:entity].id, @supporters[:np_supporter_with_add][:entity].id, @supporters[:supporter_from_other_np][:entity].id, @supporters[:np_supporter_with_no_changes][:entity].id], + create_cfm_data(@add_cfm, @delete_cfm)) expect(CustomFieldJoin.where("supporter_id = ? ", @supporters[:np_supporter_with_some_of_both][:entity].id).count).to eq 2 @@ -205,31 +190,27 @@ expect(CustomFieldJoin.where("supporter_id = ?", @supporters[:np_supporter_with_no_changes][:entity].id).count).to eq 2 expect(CustomFieldJoin.count).to eq 16 - - end - it 'id, updated_at, created_at changes are stripped' do - + it "id, updated_at, created_at changes are stripped" do invalid_id = 10000000 Timecop.freeze(2020, 9, 1, 12, 0, 0) { - results = InsertCustomFieldJoins::in_bulk(@nonprofit.id, - [@supporters[:np_supporter_with_add][:entity].id], - [{custom_field_master_id: 25, value: "CFM value 25", id: invalid_id, created_at: Time.now.ago(3000), updated_at: Time.now.ago(2999)}]) + results = InsertCustomFieldJoins.in_bulk(@nonprofit.id, + [@supporters[:np_supporter_with_add][:entity].id], + [{custom_field_master_id: 25, value: "CFM value 25", id: invalid_id, created_at: Time.now.ago(3000), updated_at: Time.now.ago(2999)}]) expected = {custom_field_master_id: 25, value: "CFM value 25", created_at: Time.now, updated_at: Time.now, supporter_id: @supporters[:np_supporter_with_add][:entity].id}.with_indifferent_access expect(results).to eq(successful_json(1, 0)) - result_tag = @supporters[:np_supporter_with_add][:entity].custom_field_joins.where('custom_field_master_id = ?', 25).first + result_tag = @supporters[:np_supporter_with_add][:entity].custom_field_joins.where("custom_field_master_id = ?", 25).first - expect(result_tag.attributes.with_indifferent_access.reject {|k, _| k == 'id'}).to eq(expected) + expect(result_tag.attributes.with_indifferent_access.reject { |k, _| k == "id" }).to eq(expected) expect(result_tag.attributes[:id]).to_not eq invalid_id } end - it 'add_to_one' do - + it "add_to_one" do expect(CustomFieldJoin.count).to eq 13 np_supporter_with_add_cfms = @supporters[:np_supporter_with_add][:entity].custom_field_joins.to_a @@ -237,73 +218,64 @@ np_supporter_with_no_changes_cfms = @supporters[:np_supporter_with_no_changes][:entity].custom_field_joins.to_a Timecop.travel(20) { - - - results = InsertCustomFieldJoins::in_bulk(@nonprofit.id, - [ - @supporters[:np_supporter_with_add][:entity].id, #add 2 - @supporters[:np_supporter_with_no_changes][:entity], # update 2 - @supporters[:np_supporter_with_some_of_both][:entity].id], #add 2, delete 1 - create_cfm_data(@add_cfm, @delete_cfm)) + results = InsertCustomFieldJoins.in_bulk(@nonprofit.id, + [ + @supporters[:np_supporter_with_add][:entity].id, # add 2 + @supporters[:np_supporter_with_no_changes][:entity], # update 2 + @supporters[:np_supporter_with_some_of_both][:entity].id + ], # add 2, delete 1 + create_cfm_data(@add_cfm, @delete_cfm)) expect(results).to eq(successful_json(6, 1)) - expect(@supporters[:np_supporter_with_no_changes][:entity].custom_field_joins).to match_array(np_supporter_with_no_changes_cfms) expect(CustomFieldJoin.where("supporter_id = ? ", @supporters[:np_supporter_with_add][:entity].id).count).to eq 5 original_db_pairs = get_original_and_db(np_supporter_with_add_cfms, CustomFieldJoin.where("supporter_id = ? and custom_field_master_id in (?)", - @supporters[:np_supporter_with_add][:entity].id, - @supporters[:np_supporter_with_add][:cfm_ids]).pluck(:id)) + @supporters[:np_supporter_with_add][:entity].id, + @supporters[:np_supporter_with_add][:cfm_ids]).pluck(:id)) - original_db_pairs.each {|orig, db| + original_db_pairs.each { |orig, db| expect(db.attributes.length).to eq(orig.attributes.length) expect(db.attributes).to eq(orig.attributes) } expect(CustomFieldJoin.where("supporter_id = ?", @supporters[:np_supporter_with_some_of_both][:entity].id).count).to eq 2 - original_db_pairs = get_original_and_db(np_supporter_with_some_of_both_cfms, CustomFieldJoin.where("supporter_id = ? and custom_field_master_id in (?)", - @supporters[:np_supporter_with_some_of_both][:entity].id, - [35]).pluck(:id)) - skip_attribs = ['updated_at', 'value'] - original_db_pairs.each {|orig, db| + @supporters[:np_supporter_with_some_of_both][:entity].id, + [35]).pluck(:id)) + skip_attribs = ["updated_at", "value"] + original_db_pairs.each { |orig, db| expect(db.attributes.length).to eq(orig.attributes.length) - expect(db.attributes.select {|key, value| !skip_attribs.include?(key)}).to eq(orig.attributes.select {|key, value| !skip_attribs.include?(key)}) - expect(db.attributes['updated_at']).to be > orig.attributes['updated_at'] - expect(db.attributes['value']).to eq "CFM value 35" - - + expect(db.attributes.select { |key, value| !skip_attribs.include?(key) }).to eq(orig.attributes.select { |key, value| !skip_attribs.include?(key) }) + expect(db.attributes["updated_at"]).to be > orig.attributes["updated_at"] + expect(db.attributes["value"]).to eq "CFM value 35" } expect(CustomFieldJoin.count).to eq 15 - } - - end - end end def successful_json(inserted, deleted) - {:json => {:inserted_count => inserted, :removed_count => deleted}, :status => :ok} + {json: {inserted_count: inserted, removed_count: deleted}, status: :ok} end - def create_cfm_data(cfm_to_add =[], cfm_to_delete=[]) + def create_cfm_data(cfm_to_add = [], cfm_to_delete = []) use_nil = true - cfm_to_add.map {|cfm| {custom_field_master_id: cfm, value: "CFM value #{cfm}"}} + cfm_to_delete.map {|cfm| - value = use_nil ? nil : '' + cfm_to_add.map { |cfm| {custom_field_master_id: cfm, value: "CFM value #{cfm}"} } + cfm_to_delete.map { |cfm| + value = use_nil ? nil : "" use_nil = !use_nil - - {custom_field_master_id: cfm, value: value}} + {custom_field_master_id: cfm, value: value} + } end def get_original_and_db(original_items, ids_to_verify) - ids_to_verify.map {|i| - original_item = original_items.find {|oi| oi[:id] == i} + ids_to_verify.map { |i| + original_item = original_items.find { |oi| oi[:id] == i } db_item = CustomFieldJoin.find(i) [original_item, db_item] } diff --git a/spec/lib/insert/insert_donation_spec.rb b/spec/lib/insert/insert_donation_spec.rb index 44d08e490..975bce505 100644 --- a/spec/lib/insert/insert_donation_spec.rb +++ b/spec/lib/insert/insert_donation_spec.rb @@ -1,9 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertDonation do - describe '.with_stripe' do - + describe ".with_stripe" do before(:each) { Settings.payment_provider.stripe_connect = true } @@ -14,416 +13,402 @@ include_context :shared_rd_donation_value_context - describe 'param validation' do - it 'does basic validation' do - validation_basic_validation { InsertDonation.with_stripe({designation: 34124, dedication: 35141, event_id: "bad", campaign_id: 'bad'}) } + describe "param validation" do + it "does basic validation" do + validation_basic_validation { InsertDonation.with_stripe({designation: 34124, dedication: 35141, event_id: "bad", campaign_id: "bad"}) } end - it 'errors out if token is invalid' do + it "errors out if token is invalid" do validation_invalid_token { InsertDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid) } end - it 'errors out if token is unauthorized' do + it "errors out if token is unauthorized" do validation_unauthorized { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: 1, supporter_id: 1, token: fake_uuid) } end - it 'errors out if token is expired' do + it "errors out if token is expired" do validation_expired { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: 1, supporter_id: 1, token: fake_uuid) } end - it 'errors out if nonprofit not vetted' do - find_error_nonprofit do - nonprofit.vetted = false - nonprofit.save! - InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) - end - end - - - describe 'errors during find if' do - it 'supporter is invalid' do - find_error_supporter { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: 55555, token: source_token.token)} + it "errors out if nonprofit not vetted" do + find_error_nonprofit do + nonprofit.vetted = false + nonprofit.save! + InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) end + end - it 'nonprofit is invalid' do - find_error_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: 55555, supporter_id: supporter.id, token: source_token.token)} + describe "errors during find if" do + it "supporter is invalid" do + find_error_supporter { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: 55555, token: source_token.token) } end - it 'campaign is invalid' do - find_error_campaign { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: 5555)} + it "nonprofit is invalid" do + find_error_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: 55555, supporter_id: supporter.id, token: source_token.token) } end - it 'event is invalid' do - find_error_event { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: 5555)} + it "campaign is invalid" do + find_error_campaign { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: 5555) } end - it 'profile is invalid' do - find_error_profile {InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: 5555)} - end + it "event is invalid" do + find_error_event { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: 5555) } + end + it "profile is invalid" do + find_error_profile { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: 5555) } + end end - describe 'errors during relationship comparison if' do - it 'supporter is deleted' do - validation_supporter_deleted { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token)} + describe "errors during relationship comparison if" do + it "supporter is deleted" do + validation_supporter_deleted { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) } end - it 'event is deleted' do + it "event is deleted" do validation_event_deleted { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id) } end - it 'campaign is deleted' do + it "campaign is deleted" do validation_campaign_deleted { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id) } end - it 'supporter doesnt belong to nonprofit' do - validation_supporter_not_with_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: other_nonprofit_supporter.id, token: source_token.token)} + it "supporter doesnt belong to nonprofit" do + validation_supporter_not_with_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: other_nonprofit_supporter.id, token: source_token.token) } end - it 'campaign doesnt belong to nonprofit' do - validation_campaign_not_with_nonprofit{ InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: other_campaign.id)} + it "campaign doesnt belong to nonprofit" do + validation_campaign_not_with_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: other_campaign.id) } end - it 'event doesnt belong to nonprofit' do - validation_event_not_with_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: other_event.id)} + it "event doesnt belong to nonprofit" do + validation_event_not_with_nonprofit { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: other_event.id) } end - it 'card doesnt belong to supporter' do - validation_card_not_with_supporter{ InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: other_source_token.token)} + it "card doesnt belong to supporter" do + validation_card_not_with_supporter { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: other_source_token.token) } end end end - it 'charge returns failed' do - handle_charge_failed { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token)} + it "charge returns failed" do + handle_charge_failed { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) } end - describe 'success' do + describe "success" do before(:each) { before_each_success } - describe 'event donation' do - - let(:result) { - InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') - } - - it 'process event donation' do - - process_event_donation { result} - - end - - it 'increases object event charge by one' do - - expect { - result - }.to change { - ObjectEvent.where(event_type: 'stripe_transaction_charge.created').count - }.by 1 - end - - it 'creates a subtransaction_payment whose creation date matches the legacy payment\'s date' do - expect(result['payment'].subtransaction_payment.created).to eq(result['payment'].date) - end + describe "event donation" do + let(:result) { + InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation") + } + + it "process event donation" do + process_event_donation { result } + end + + it "increases object event charge by one" do + expect { + result + }.to change { + ObjectEvent.where(event_type: "stripe_transaction_charge.created").count + }.by 1 + end + + it "creates a subtransaction_payment whose creation date matches the legacy payment's date" do + expect(result["payment"].subtransaction_payment.created).to eq(result["payment"].date) + end + end + + describe "campaign donation" do + let(:result) { + InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation") + } + + it "process campaign donation" do + process_campaign_donation { result } + end + + it "increases object event charge by one" do + expect { + result + }.to change { + ObjectEvent.where(event_type: "stripe_transaction_charge.created").count + }.by 1 + end + + it "creates a subtransaction_payment whose creation date matches the legacy payment's date" do + expect(result["payment"].subtransaction_payment.created).to eq(result["payment"].date) + end end + describe "general donation" do + let(:result) { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation") } + it "processes general donation" do + process_general_donation { result } + end - describe 'campaign donation' do - - let(:result) { - InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation') - } - - it 'process campaign donation' do - process_campaign_donation {result} - end - - it 'increases object event charge by one' do - - expect { - result - }.to change { - ObjectEvent.where(event_type: 'stripe_transaction_charge.created').count - }.by 1 - end - - it 'creates a subtransaction_payment whose creation date matches the legacy payment\'s date' do - expect(result['payment'].subtransaction_payment.created).to eq(result['payment'].date) - end - end - describe 'general donation' do - let(:result) { InsertDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation')} - it 'processes general donation' do - process_general_donation{result } - end - - it 'increases object event charge by one' do - - expect { - result - }.to change { - ObjectEvent.where(event_type: 'stripe_transaction_charge.created').count - }.by 1 - end - end + it "increases object event charge by one" do + expect { + result + }.to change { + ObjectEvent.where(event_type: "stripe_transaction_charge.created").count + }.by 1 + end + end end end - describe '.offsite' do - include_context :shared_rd_donation_value_context - describe 'failures' do - - it 'fails if amount is missing' do - expect do - described_class.offsite( - { - nonprofit_id: nonprofit.id, - supporter_id: supporter.id - }.with_indifferent_access - ) - end.to raise_error(ParamValidation::ValidationError) - end - end - - describe 'success' do - - describe 'general offsite create' do - subject(:trx) do - result = described_class.offsite( - { - amount: charge_amount, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - date: created_time.to_s, - offsite_payment: ActionController::Parameters.new({ - check_number: 1234, - kind: "check" - }) - }.with_indifferent_access - ) - Payment.find(result[:json]['payment']['id']).trx - end - - let(:created_time) { 1.day.from_now } - let(:common_builder) do - { - 'supporter' => supporter.id, 'nonprofit' => nonprofit.id - } - end - - let(:common_builder_expanded) do - { - 'supporter' => supporter_builder_expanded, 'nonprofit' => np_builder_expanded - } - end - - let(:common_builder_with_trx_id) do - common_builder.merge( - { - 'transaction' => match_houid('trx') - } - ) - end - - let(:common_builder_with_trx) do - common_builder.merge( - { - 'transaction' => transaction_builder - } - ) - end - - let(:np_builder_expanded) do - { - 'id' => nonprofit.id, - 'name' => nonprofit.name, - 'object' => 'nonprofit' - } - end - - let(:supporter_builder_expanded) do - supporter_to_builder_base.merge({ 'name' => 'Fake Supporter Name' }) - end - - let(:transaction_builder) do - common_builder.merge( - { - 'id' => match_houid('trx'), - 'object' => 'transaction', - 'amount' => { - 'cents' => charge_amount, - 'currency' => 'usd' - }, - 'created' => created_time.to_i, - 'subtransaction' => offline_transaction_id_only, - 'subtransaction_payments' => [offline_transaction_charge_id_only], - 'transaction_assignments' => [donation_id_only] - } - ) - end - - let(:transaction_builder_expanded) do - transaction_builder.merge( - common_builder_expanded, - { - 'subtransaction' => offline_transaction_builder, - 'subtransaction_payments' => [offline_transaction_charge_builder], - 'transaction_assignments' => [donation_builder] - } - ) - end - - let(:offline_transaction_id_only) do - { - 'id' => match_houid('offlinetrx'), - 'object' => 'offline_transaction', - 'type' => 'subtransaction' - } - end - - let(:offline_transaction_builder) do - offline_transaction_id_only.merge( - common_builder_with_trx_id, - { - 'initial_amount' => { - 'cents' => charge_amount, - 'currency' => 'usd' - }, - - 'net_amount' => { - 'cents' => charge_amount, - 'currency' => 'usd' - }, - - 'payments' => [offline_transaction_charge_id_only], - 'created' => created_time.to_i - } - ) - end - - let(:offline_transaction_builder_expanded) do - offline_transaction_builder.merge( - common_builder_with_trx, - common_builder_expanded, - { - 'payments' => [offline_transaction_charge_builder] - } - ) - end - - let(:offline_transaction_charge_id_only) do - { - 'id' => match_houid('offtrxchrg'), - 'object' => 'offline_transaction_charge', - 'type' => 'payment' - } - end - - let(:offline_transaction_charge_builder) do - offline_transaction_charge_id_only.merge( - common_builder_with_trx_id, - { - 'gross_amount' => { - 'cents' => charge_amount, - 'currency' => 'usd' - }, - 'net_amount' => { - 'cents' => charge_amount, - 'currency' => 'usd' - }, - 'fee_total' => { - 'cents' => 0, - 'currency' => 'usd' - }, - 'subtransaction' => offline_transaction_id_only, - 'created' => created_time.to_i - } - ) - end - - let(:offline_transaction_charge_builder_expanded) do - offline_transaction_charge_builder.merge( - common_builder_with_trx, - common_builder_expanded, - { - 'subtransaction' => offline_transaction_builder - } - ) - end - - let(:donation_id_only) do - { - 'id' => match_houid('don'), - 'object' => 'donation', - 'type' => 'trx_assignment' - } - end - - let(:donation_builder) do - donation_id_only.merge(common_builder_with_trx_id, - { - 'amount' => { - 'cents' => charge_amount, - 'currency' => 'usd' - }, - 'designation' => nil - } - ) - end - - let(:donation_builder_expanded) do - donation_builder.merge(common_builder_with_trx, common_builder_expanded) - end - - - it 'creates an offline_transaction_charge.created object event' do - expect { trx }.to change { - ObjectEvent.where(event_type: 'offline_transaction_charge.created').count - }.by 1 - end - - it 'object event has the correct information' do - offline_transaction_charge = trx.payments.first.paymentable - object_event = offline_transaction_charge.object_events.first - - expect(object_event.object_json).to include_json( - id: object_event.houid, - type: 'offline_transaction_charge.created', - object: 'object_event', - created: object_event.created.to_i, - data: { - object: { - id: offline_transaction_charge.houid, - type: 'payment', - legacy_id: offline_transaction_charge.legacy_payment.id, - legacy_nonprofit: offline_transaction_charge.nonprofit.id, - object: 'offline_transaction_charge', - created: offline_transaction_charge.created.to_i, - nonprofit: nonprofit.houid, - 'supporter' => { - 'id' => offline_transaction_charge.supporter.houid - }, - fee_total: { - cents: offline_transaction_charge.fee_total_as_money.cents, - currency: 'usd' - }, - net_amount: { - cents: offline_transaction_charge.net_amount_as_money.cents, - currency: 'usd' - }, - gross_amount: { - cents: offline_transaction_charge.gross_amount_as_money.cents, - currency: 'usd' - }, - transaction: offline_transaction_charge.subtransaction_payment.trx.houid, - check_number: "1234", - kind: "check" - } - } - ) - - end - end - end + describe ".offsite" do + include_context :shared_rd_donation_value_context + describe "failures" do + it "fails if amount is missing" do + expect do + described_class.offsite( + { + nonprofit_id: nonprofit.id, + supporter_id: supporter.id + }.with_indifferent_access + ) + end.to raise_error(ParamValidation::ValidationError) + end + end + + describe "success" do + describe "general offsite create" do + subject(:trx) do + result = described_class.offsite( + { + amount: charge_amount, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + date: created_time.to_s, + offsite_payment: ActionController::Parameters.new({ + check_number: 1234, + kind: "check" + }) + }.with_indifferent_access + ) + Payment.find(result[:json]["payment"]["id"]).trx + end + + let(:created_time) { 1.day.from_now } + let(:common_builder) do + { + "supporter" => supporter.id, "nonprofit" => nonprofit.id + } + end + + let(:common_builder_expanded) do + { + "supporter" => supporter_builder_expanded, "nonprofit" => np_builder_expanded + } + end + + let(:common_builder_with_trx_id) do + common_builder.merge( + { + "transaction" => match_houid("trx") + } + ) + end + + let(:common_builder_with_trx) do + common_builder.merge( + { + "transaction" => transaction_builder + } + ) + end + + let(:np_builder_expanded) do + { + "id" => nonprofit.id, + "name" => nonprofit.name, + "object" => "nonprofit" + } + end + + let(:supporter_builder_expanded) do + supporter_to_builder_base.merge({"name" => "Fake Supporter Name"}) + end + + let(:transaction_builder) do + common_builder.merge( + { + "id" => match_houid("trx"), + "object" => "transaction", + "amount" => { + "cents" => charge_amount, + "currency" => "usd" + }, + "created" => created_time.to_i, + "subtransaction" => offline_transaction_id_only, + "subtransaction_payments" => [offline_transaction_charge_id_only], + "transaction_assignments" => [donation_id_only] + } + ) + end + + let(:transaction_builder_expanded) do + transaction_builder.merge( + common_builder_expanded, + { + "subtransaction" => offline_transaction_builder, + "subtransaction_payments" => [offline_transaction_charge_builder], + "transaction_assignments" => [donation_builder] + } + ) + end + + let(:offline_transaction_id_only) do + { + "id" => match_houid("offlinetrx"), + "object" => "offline_transaction", + "type" => "subtransaction" + } + end + + let(:offline_transaction_builder) do + offline_transaction_id_only.merge( + common_builder_with_trx_id, + { + "initial_amount" => { + "cents" => charge_amount, + "currency" => "usd" + }, + + "net_amount" => { + "cents" => charge_amount, + "currency" => "usd" + }, + + "payments" => [offline_transaction_charge_id_only], + "created" => created_time.to_i + } + ) + end + + let(:offline_transaction_builder_expanded) do + offline_transaction_builder.merge( + common_builder_with_trx, + common_builder_expanded, + { + "payments" => [offline_transaction_charge_builder] + } + ) + end + + let(:offline_transaction_charge_id_only) do + { + "id" => match_houid("offtrxchrg"), + "object" => "offline_transaction_charge", + "type" => "payment" + } + end + + let(:offline_transaction_charge_builder) do + offline_transaction_charge_id_only.merge( + common_builder_with_trx_id, + { + "gross_amount" => { + "cents" => charge_amount, + "currency" => "usd" + }, + "net_amount" => { + "cents" => charge_amount, + "currency" => "usd" + }, + "fee_total" => { + "cents" => 0, + "currency" => "usd" + }, + "subtransaction" => offline_transaction_id_only, + "created" => created_time.to_i + } + ) + end + + let(:offline_transaction_charge_builder_expanded) do + offline_transaction_charge_builder.merge( + common_builder_with_trx, + common_builder_expanded, + { + "subtransaction" => offline_transaction_builder + } + ) + end + + let(:donation_id_only) do + { + "id" => match_houid("don"), + "object" => "donation", + "type" => "trx_assignment" + } + end + + let(:donation_builder) do + donation_id_only.merge(common_builder_with_trx_id, + { + "amount" => { + "cents" => charge_amount, + "currency" => "usd" + }, + "designation" => nil + }) + end + + let(:donation_builder_expanded) do + donation_builder.merge(common_builder_with_trx, common_builder_expanded) + end + + it "creates an offline_transaction_charge.created object event" do + expect { trx }.to change { + ObjectEvent.where(event_type: "offline_transaction_charge.created").count + }.by 1 + end + + it "object event has the correct information" do + offline_transaction_charge = trx.payments.first.paymentable + object_event = offline_transaction_charge.object_events.first + + expect(object_event.object_json).to include_json( + id: object_event.houid, + type: "offline_transaction_charge.created", + object: "object_event", + created: object_event.created.to_i, + data: { + object: { + :id => offline_transaction_charge.houid, + :type => "payment", + :legacy_id => offline_transaction_charge.legacy_payment.id, + :legacy_nonprofit => offline_transaction_charge.nonprofit.id, + :object => "offline_transaction_charge", + :created => offline_transaction_charge.created.to_i, + :nonprofit => nonprofit.houid, + "supporter" => { + "id" => offline_transaction_charge.supporter.houid + }, + :fee_total => { + cents: offline_transaction_charge.fee_total_as_money.cents, + currency: "usd" + }, + :net_amount => { + cents: offline_transaction_charge.net_amount_as_money.cents, + currency: "usd" + }, + :gross_amount => { + cents: offline_transaction_charge.gross_amount_as_money.cents, + currency: "usd" + }, + :transaction => offline_transaction_charge.subtransaction_payment.trx.houid, + :check_number => "1234", + :kind => "check" + } + } + ) + end + end + end end end diff --git a/spec/lib/insert/insert_duplicate_spec.rb b/spec/lib/insert/insert_duplicate_spec.rb index adf0d9e68..2522db10e 100644 --- a/spec/lib/insert/insert_duplicate_spec.rb +++ b/spec/lib/insert/insert_duplicate_spec.rb @@ -1,31 +1,28 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertDuplicate do - - before(:all) { Timecop.freeze(2020, 5, 5) } - after(:all){ + after(:all) { Timecop.return } - let(:nonprofit) {force_create(:nonprofit)} - let(:profile) {force_create(:profile)} - let(:dates) {{ - ten_days_from_now: DateTime.new(2020,5,15), - ten_days_from_now_plus_4_hours: DateTime.new(2020,5,15, 4), - two_days_from_now: DateTime.new(2020,5,7), - two_days_from_now_plus_4_hours: DateTime.new(2020,5,7, 4), - two_days_ago: DateTime.new(2020,5,3), - two_days_ago_plus_4_hours: DateTime.new(2020,5,3, 4) - - }} - - describe '.campaign' do - + let(:nonprofit) { force_create(:nonprofit) } + let(:profile) { force_create(:profile) } + let(:dates) { + { + ten_days_from_now: DateTime.new(2020, 5, 15), + ten_days_from_now_plus_4_hours: DateTime.new(2020, 5, 15, 4), + two_days_from_now: DateTime.new(2020, 5, 7), + two_days_from_now_plus_4_hours: DateTime.new(2020, 5, 7, 4), + two_days_ago: DateTime.new(2020, 5, 3), + two_days_ago_plus_4_hours: DateTime.new(2020, 5, 3, 4) + } + } + describe ".campaign" do def set_campaign_date(end_date) @end_date = end_date end @@ -33,321 +30,316 @@ def set_campaign_date(end_date) before(:each) { set_campaign_date(dates[:ten_days_from_now]) } - let(:campaign){force_create(:campaign, :name => campaign_name, :nonprofit => nonprofit, end_datetime: @end_date, slug: campaign_slug, goal_amount: 20000, published: true, profile: profile)} - - let(:campaign_gift_option) {force_create(:campaign_gift_option, name: cgo_name, campaign: campaign)} - let(:cgo_name) { "cgo name"} - let(:campaign_name) {"campaign_name is so long that it must be shortened down"} - let(:copy_name){ "campaign_name is so long that it must b (2020-05-05 copy) 00"} - let(:campaign_slug) {"campaign_slug"} - let(:copy_slug) {"campaign_slug_copy_00"} + let(:campaign) { force_create(:campaign, name: campaign_name, nonprofit: nonprofit, end_datetime: @end_date, slug: campaign_slug, goal_amount: 20000, published: true, profile: profile) } + + let(:campaign_gift_option) { force_create(:campaign_gift_option, name: cgo_name, campaign: campaign) } + let(:cgo_name) { "cgo name" } + let(:campaign_name) { "campaign_name is so long that it must be shortened down" } + let(:copy_name) { "campaign_name is so long that it must b (2020-05-05 copy) 00" } + let(:campaign_slug) { "campaign_slug" } + let(:copy_slug) { "campaign_slug_copy_00" } let(:common_result_attributes) { { - nonprofit_id: nonprofit.id, - parent_campaign_id: nil, - reason_for_supporting: nil, - profile_id: profile.id, - :background_image => nil, - widget_description_id: nil, - :body => nil, - :created_at => Time.now, - :deleted => false, - :goal_amount => 20000, - :hide_activity_feed => nil, - :hide_custom_amounts => nil, - :hide_goal => nil, - :hide_thermometer => nil, - :hide_title => nil, - :main_image => nil, - :published => false, - :receipt_message => nil, - :show_recurring_amount => false, - :show_total_count => true, - :show_total_raised => true, - :summary => nil, - :tagline => nil, - :total_raised => nil, - :total_supporters => 1, - :updated_at => Time.now, - :url => nil, - :video_url => nil, - :vimeo_video_id => nil, - :youtube_video_id => nil, - starting_point: 0, - goal_is_in_supporters: nil, - banner_image: nil, - default_reason_for_supporting: nil, - name: copy_name, - - slug: copy_slug, - external_identifier: nil + nonprofit_id: nonprofit.id, + parent_campaign_id: nil, + reason_for_supporting: nil, + profile_id: profile.id, + background_image: nil, + widget_description_id: nil, + body: nil, + created_at: Time.now, + deleted: false, + goal_amount: 20000, + hide_activity_feed: nil, + hide_custom_amounts: nil, + hide_goal: nil, + hide_thermometer: nil, + hide_title: nil, + main_image: nil, + published: false, + receipt_message: nil, + show_recurring_amount: false, + show_total_count: true, + show_total_raised: true, + summary: nil, + tagline: nil, + total_raised: nil, + total_supporters: 1, + updated_at: Time.now, + url: nil, + video_url: nil, + vimeo_video_id: nil, + youtube_video_id: nil, + starting_point: 0, + goal_is_in_supporters: nil, + banner_image: nil, + default_reason_for_supporting: nil, + name: copy_name, + + slug: copy_slug, + external_identifier: nil }.with_indifferent_access } - describe 'param validation' do - it 'does basic validation' do - expect {InsertDuplicate.campaign(nil, nil)}.to(raise_error {|error| + describe "param validation" do + it "does basic validation" do + expect { InsertDuplicate.campaign(nil, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :campaign_id, name: :required}, - {key: :campaign_id, name: :is_integer}, - {key: :profile_id, name: :required}, - {key: :profile_id, name: :is_integer}]) - + {key: :campaign_id, name: :is_integer}, + {key: :profile_id, name: :required}, + {key: :profile_id, name: :is_integer}]) }) end - it 'does campaign existence validation' do - expect {InsertDuplicate.campaign(999, 999)}.to(raise_error {|error| + it "does campaign existence validation" do + expect { InsertDuplicate.campaign(999, 999) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :campaign_id}]) }) end - it 'does profile existence validation' do - expect {InsertDuplicate.campaign(campaign.id, 999)}.to(raise_error {|error| + it "does profile existence validation" do + expect { InsertDuplicate.campaign(campaign.id, 999) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :profile_id}]) }) end end - it 'copies a nonending campaign properly' do - set_campaign_date(nil) - campaign_gift_option - result = InsertDuplicate.campaign(campaign.id, profile.id) - expect(Campaign.count).to eq 2 - - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, - end_datetime: nil, - banner_image: nil - }).with_indifferent_access) - validate_cgo(result) - end - - it 'copies a soon to finish campaign properly' do - set_campaign_date(dates[:two_days_from_now]) - campaign_gift_option - result = InsertDuplicate.campaign(campaign.id, profile.id) - expect(Campaign.count).to eq 2 + it "copies a nonending campaign properly" do + set_campaign_date(nil) + campaign_gift_option + result = InsertDuplicate.campaign(campaign.id, profile.id) + expect(Campaign.count).to eq 2 + + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, + end_datetime: nil, + banner_image: nil + } + ).with_indifferent_access) + validate_cgo(result) + end - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, + it "copies a soon to finish campaign properly" do + set_campaign_date(dates[:two_days_from_now]) + campaign_gift_option + result = InsertDuplicate.campaign(campaign.id, profile.id) + expect(Campaign.count).to eq 2 - end_datetime: Time.utc(2020,5,12) + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, - }).with_indifferent_access) - validate_cgo(result) - end + end_datetime: Time.utc(2020, 5, 12) - it 'copies a finished campaign properly' do - set_campaign_date(dates[:two_days_ago]) - campaign_gift_option - result = InsertDuplicate.campaign(campaign.id, profile.id) - expect(Campaign.count).to eq 2 - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, + } + ).with_indifferent_access) + validate_cgo(result) + end - end_datetime: Time.utc(2020,5,12) + it "copies a finished campaign properly" do + set_campaign_date(dates[:two_days_ago]) + campaign_gift_option + result = InsertDuplicate.campaign(campaign.id, profile.id) + expect(Campaign.count).to eq 2 + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, - }).with_indifferent_access) + end_datetime: Time.utc(2020, 5, 12) - validate_cgo(result) - end + } + ).with_indifferent_access) - it 'copies a future campaign properly' do - campaign_gift_option - result = InsertDuplicate.campaign(campaign.id, profile.id) - expect(Campaign.count).to eq 2 - - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, - end_datetime: campaign.end_datetime.to_time - }).with_indifferent_access) - validate_cgo(result) - end + validate_cgo(result) + end + it "copies a future campaign properly" do + campaign_gift_option + result = InsertDuplicate.campaign(campaign.id, profile.id) + expect(Campaign.count).to eq 2 + + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, + end_datetime: campaign.end_datetime.to_time + } + ).with_indifferent_access) + validate_cgo(result) + end def validate_cgo(new_campaign) - old_campaign = campaign expect(CampaignGiftOption.count).to eq 2 old_cgo = old_campaign.campaign_gift_options.first new_cgo = new_campaign.campaign_gift_options.first expect(old_cgo.id).to_not eq new_cgo.id expect(old_cgo.campaign_id).to_not eq new_cgo.campaign_id - expect(old_cgo.attributes.except('id', 'campaign_id')).to eq new_cgo.attributes.except("id", 'campaign_id') - + expect(old_cgo.attributes.except("id", "campaign_id")).to eq new_cgo.attributes.except("id", "campaign_id") end - end - describe '.event' do - - + describe ".event" do def set_event_start_time(start_time, end_time) @start_time = start_time @end_time = end_time end - before(:each) { set_event_start_time(dates[:ten_days_from_now], dates[:ten_days_from_now_plus_4_hours]) allow_any_instance_of(Event).to receive(:geocode).and_return(nil) } - - let(:event){ - force_create(:event, :name => event_name, :nonprofit => nonprofit, start_datetime: @start_time, end_datetime: @end_time, slug: event_slug, published: true, profile: profile) + let(:event) { + force_create(:event, name: event_name, nonprofit: nonprofit, start_datetime: @start_time, end_datetime: @end_time, slug: event_slug, published: true, profile: profile) } - let(:ticket_level) {force_create(:ticket_level, :name =>ticket_level_name, :amount_dollars => 500, event: event)} - let(:event_discount) {force_create(:event_discount, :code =>"code", event: event)} - let(:cgo_name) { "cgo name"} - let(:ticket_level_name) { "cgo name"} - let(:event_name) {"campaign_name is so long that it must be shortened down"} - let(:copy_name){ "campaign_name is so long that it must b (2020-05-05 copy) 00"} - let(:event_slug) {"campaign_slug"} - let(:copy_slug) {"campaign_slug_copy_00"} + let(:ticket_level) { force_create(:ticket_level, name: ticket_level_name, amount_dollars: 500, event: event) } + let(:event_discount) { force_create(:event_discount, code: "code", event: event) } + let(:cgo_name) { "cgo name" } + let(:ticket_level_name) { "cgo name" } + let(:event_name) { "campaign_name is so long that it must be shortened down" } + let(:copy_name) { "campaign_name is so long that it must b (2020-05-05 copy) 00" } + let(:event_slug) { "campaign_slug" } + let(:copy_slug) { "campaign_slug_copy_00" } let(:common_result_attributes) { { - nonprofit_id: nonprofit.id, - profile_id: profile.id, - :background_image => nil, - :body => nil, - :created_at => Time.now, - :deleted => false, - :hide_activity_feed => nil, - :hide_title => nil, - :main_image => nil, - :published => false, - :receipt_message => nil, - :summary => nil, - :tagline => nil, - :total_raised => 0, - :updated_at => Time.now, - name: copy_name, - slug: copy_slug, - :address => "100 N Appleton St", - :city => "Appleton", - :directions => nil, - :latitude => nil, - :location => nil, - :longitude => nil, - organizer_email: profile.user.email, - :state_code => "WI", - :venue_name => nil, - :zip_code => nil, - show_total_count: false, - - show_total_raised: false - + nonprofit_id: nonprofit.id, + profile_id: profile.id, + background_image: nil, + body: nil, + created_at: Time.now, + deleted: false, + hide_activity_feed: nil, + hide_title: nil, + main_image: nil, + published: false, + receipt_message: nil, + summary: nil, + tagline: nil, + total_raised: 0, + updated_at: Time.now, + name: copy_name, + slug: copy_slug, + address: "100 N Appleton St", + city: "Appleton", + directions: nil, + latitude: nil, + location: nil, + longitude: nil, + organizer_email: profile.user.email, + state_code: "WI", + venue_name: nil, + zip_code: nil, + show_total_count: false, + + show_total_raised: false }.with_indifferent_access } - describe 'param validation' do - it 'does basic validation' do - expect {InsertDuplicate.event(nil, nil)}.to(raise_error {|error| + describe "param validation" do + it "does basic validation" do + expect { InsertDuplicate.event(nil, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id, name: :required}, - {key: :event_id, name: :is_integer}, - {key: :profile_id, name: :required}, - {key: :profile_id, name: :is_integer}]) - + {key: :event_id, name: :is_integer}, + {key: :profile_id, name: :required}, + {key: :profile_id, name: :is_integer}]) }) end - it 'does event existence validation' do - expect {InsertDuplicate.event(999, 999)}.to(raise_error {|error| + it "does event existence validation" do + expect { InsertDuplicate.event(999, 999) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id}]) }) end - it 'does profile existence validation' do - expect {InsertDuplicate.event(event.id, 999)}.to(raise_error {|error| + it "does profile existence validation" do + expect { InsertDuplicate.event(event.id, 999) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :profile_id}]) }) end end - it 'copies a soon to start event properly' do - set_event_start_time(dates[:two_days_from_now], dates[:two_days_from_now_plus_4_hours]) - ticket_level - event_discount - - result = InsertDuplicate.event(event.id, profile.id) - expect(Event.count).to eq 2 - result.attributes['start_datetime'] = result.attributes['start_datetime'].to_datetime - result.attributes['end_datetime'] = result.attributes['end_datetime'].to_datetime - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, - start_datetime: DateTime.new(2020, 5, 12), - end_datetime: DateTime.new(2020,5,12, 4) - }).with_indifferent_access) - validate_tls(result) - validate_eds(result) - end + it "copies a soon to start event properly" do + set_event_start_time(dates[:two_days_from_now], dates[:two_days_from_now_plus_4_hours]) + ticket_level + event_discount + + result = InsertDuplicate.event(event.id, profile.id) + expect(Event.count).to eq 2 + result.attributes["start_datetime"] = result.attributes["start_datetime"].to_datetime + result.attributes["end_datetime"] = result.attributes["end_datetime"].to_datetime + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, + start_datetime: DateTime.new(2020, 5, 12), + end_datetime: DateTime.new(2020, 5, 12, 4) + } + ).with_indifferent_access) + validate_tls(result) + validate_eds(result) + end - it 'copies a finished event properly' do - set_event_start_time(dates[:two_days_ago], dates[:two_days_ago_plus_4_hours]) - ticket_level - event_discount - result = InsertDuplicate.event(event.id, profile.id) - expect(Event.count).to eq 2 + it "copies a finished event properly" do + set_event_start_time(dates[:two_days_ago], dates[:two_days_ago_plus_4_hours]) + ticket_level + event_discount + result = InsertDuplicate.event(event.id, profile.id) + expect(Event.count).to eq 2 - result.attributes['start_datetime'] = result.attributes['start_datetime'] + result.attributes["start_datetime"] = result.attributes["start_datetime"] - result.attributes['end_datetime'] = result.attributes['end_datetime'].to_datetime - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, + result.attributes["end_datetime"] = result.attributes["end_datetime"].to_datetime + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, - start_datetime: Time.utc(2020,5,12), - end_datetime: Time.utc(2020,5,12, 4) + start_datetime: Time.utc(2020, 5, 12), + end_datetime: Time.utc(2020, 5, 12, 4) - }).with_indifferent_access) + } + ).with_indifferent_access) - validate_tls(result) - validate_eds(result) - end + validate_tls(result) + validate_eds(result) + end - it 'copies a future event properly' do - ticket_level - event_discount - result = InsertDuplicate.event(event.id, profile.id) - expect(Event.count).to eq 2 - result.attributes['start_datetime'] = result.attributes['start_datetime'].to_datetime - result.attributes['end_datetime'] = result.attributes['end_datetime'].to_datetime - expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( - { - id: result.id, - start_datetime: event.start_datetime.to_time, - end_datetime: event.end_datetime.to_time - }).with_indifferent_access) - validate_tls(result) - validate_eds(result) - end + it "copies a future event properly" do + ticket_level + event_discount + result = InsertDuplicate.event(event.id, profile.id) + expect(Event.count).to eq 2 + result.attributes["start_datetime"] = result.attributes["start_datetime"].to_datetime + result.attributes["end_datetime"] = result.attributes["end_datetime"].to_datetime + expect(result.attributes.with_indifferent_access).to eq(common_result_attributes.merge( + { + id: result.id, + start_datetime: event.start_datetime.to_time, + end_datetime: event.end_datetime.to_time + } + ).with_indifferent_access) + validate_tls(result) + validate_eds(result) + end - context 'when there are misc_event_infos to be copied' do - before do - event.create_misc_event_info - event.misc_event_info.custom_get_tickets_button_label = 'Giving Options' - event.misc_event_info.save! - end - subject { InsertDuplicate.event(event.id, profile.id) } - it 'copies custom_get_tickets_button_label from misc_event_info' do - expect(subject.misc_event_info.custom_get_tickets_button_label).to eq('Giving Options') - end + context "when there are misc_event_infos to be copied" do + before do + event.create_misc_event_info + event.misc_event_info.custom_get_tickets_button_label = "Giving Options" + event.misc_event_info.save! end - + subject { InsertDuplicate.event(event.id, profile.id) } + it "copies custom_get_tickets_button_label from misc_event_info" do + expect(subject.misc_event_info.custom_get_tickets_button_label).to eq("Giving Options") + end + end def validate_tls(new_event) old_event = event @@ -356,7 +348,7 @@ def validate_tls(new_event) new_tl = new_event.ticket_levels.first expect(old_tl.id).to_not eq new_tl.id expect(old_tl.event_id).to_not eq new_tl.event_id - expect(old_tl.attributes.except('id', 'event_id')).to eq (new_tl.attributes.except('id', 'event_id')) + expect(old_tl.attributes.except("id", "event_id")).to eq(new_tl.attributes.except("id", "event_id")) end def validate_eds(new_event) @@ -366,8 +358,7 @@ def validate_eds(new_event) new_tl = new_event.event_discounts.first expect(old_tl.id).to_not eq new_tl.id expect(old_tl.event_id).to_not eq new_tl.event_id - expect(old_tl.attributes.except('id', 'event_id')).to eq (new_tl.attributes.except('id', 'event_id')) + expect(old_tl.attributes.except("id", "event_id")).to eq(new_tl.attributes.except("id", "event_id")) end - end end diff --git a/spec/lib/insert/insert_email_lists_spec.rb b/spec/lib/insert/insert_email_lists_spec.rb index 880b5e218..84b712fe6 100644 --- a/spec/lib/insert/insert_email_lists_spec.rb +++ b/spec/lib/insert/insert_email_lists_spec.rb @@ -1,49 +1,53 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - -describe InsertEmailLists do - let(:nonprofit) { force_create(:nonprofit)} - let(:other_nonprofit) { force_create(:nonprofit)} - let(:tag_masters) { [ - force_create(:tag_master, nonprofit: nonprofit, name: 'with_list'), - force_create(:tag_master, nonprofit: nonprofit, name: 'without_list'), - force_create(:tag_master, nonprofit: nonprofit, name: 'deleted', deleted:true), - force_create(:tag_master, nonprofit: other_nonprofit, name: 'other__with_list'), - force_create(:tag_master, nonprofit: other_nonprofit, name: 'other__without_list') - ]} - - let(:email_lists) { [ - force_create(:email_list, nonprofit: nonprofit, tag_master: TagMaster.where(name: 'with_list').first, mailchimp_list_id: "with_list__mc_list", list_name: "with_list__mc_list__name"), - force_create(:email_list, nonprofit: other_nonprofit, tag_master: TagMaster.where(name: 'other__with_list').first, mailchimp_list_id: "other__with_list__mc_list", list_name: "other__with_list__mc_list__name") - ]} +require "rails_helper" + +describe InsertEmailLists do + let(:nonprofit) { force_create(:nonprofit) } + let(:other_nonprofit) { force_create(:nonprofit) } + let(:tag_masters) { + [ + force_create(:tag_master, nonprofit: nonprofit, name: "with_list"), + force_create(:tag_master, nonprofit: nonprofit, name: "without_list"), + force_create(:tag_master, nonprofit: nonprofit, name: "deleted", deleted: true), + force_create(:tag_master, nonprofit: other_nonprofit, name: "other__with_list"), + force_create(:tag_master, nonprofit: other_nonprofit, name: "other__without_list") + ] + } + + let(:email_lists) { + [ + force_create(:email_list, nonprofit: nonprofit, tag_master: TagMaster.where(name: "with_list").first, mailchimp_list_id: "with_list__mc_list", list_name: "with_list__mc_list__name"), + force_create(:email_list, nonprofit: other_nonprofit, tag_master: TagMaster.where(name: "other__with_list").first, mailchimp_list_id: "other__with_list__mc_list", list_name: "other__with_list__mc_list__name") + ] + } let(:added_correctly) { "added correctly" } - let(:list_name) {"list name" } - let(:list_id){ "list id"} + let(:list_name) { "list name" } + let(:list_id) { "list id" } - let(:tag_master_id) { tag_masters[1].id} - let(:inserted_result) { [{name: list_name, id: list_id, tag_master_id: tag_master_id}]} + let(:tag_master_id) { tag_masters[1].id } + let(:inserted_result) { [{name: list_name, id: list_id, tag_master_id: tag_master_id}] } - before(:each) {tag_masters; email_lists } + before(:each) { + tag_masters + email_lists + } - - it 'delete all lists' do - expect(Mailchimp).to receive(:delete_mailchimp_lists).with(nonprofit.id, ['with_list__mc_list']).and_return "deleted correctly" + it "delete all lists" do + expect(Mailchimp).to receive(:delete_mailchimp_lists).with(nonprofit.id, ["with_list__mc_list"]).and_return "deleted correctly" result = InsertEmailLists.for_mailchimp(nonprofit.id, []) - expected = {deleted: [{"mailchimp_list_id" => 'with_list__mc_list'}], - deleted_result: "deleted correctly" - } + expected = {deleted: [{"mailchimp_list_id" => "with_list__mc_list"}], + deleted_result: "deleted correctly"} expect(result).to eq expected expect(email_lists[1].reload).to be_truthy expect(EmailList.count).to be 1 end - it 'add lists but not delete' do - + it "add lists but not delete" do expect(Mailchimp).to receive(:delete_mailchimp_lists).with(nonprofit.id, []).and_return([]) expect(Mailchimp).to receive(:create_mailchimp_lists).with(nonprofit.id, [tag_master_id]).and_return(inserted_result) - result = InsertEmailLists.for_mailchimp(nonprofit.id, [email_lists[0].tag_master.id, tag_master_id]) + result = InsertEmailLists.for_mailchimp(nonprofit.id, [email_lists[0].tag_master.id, tag_master_id]) el = EmailList.where(list_name: list_name).first @@ -67,29 +71,27 @@ expect(EmailList.count).to eq 3 end - it 'add lists and delete' do - - + it "add lists and delete" do tag_master_list_to_delete = email_lists[0].mailchimp_list_id inserted_result = [{name: list_name, id: list_id, tag_master_id: tag_master_id}] expect(Mailchimp).to receive(:delete_mailchimp_lists).with(nonprofit.id, [tag_master_list_to_delete]).and_return "deleted correctly" expect(Mailchimp).to receive(:create_mailchimp_lists).with(nonprofit.id, [tag_master_id]).and_return(inserted_result) - result = InsertEmailLists.for_mailchimp(nonprofit.id, [ tag_master_id, email_lists[1].tag_master.id]) + result = InsertEmailLists.for_mailchimp(nonprofit.id, [tag_master_id, email_lists[1].tag_master.id]) el = EmailList.where(list_name: list_name).first expected = { - inserted_lists: [{ - id: el.id, - nonprofit_id: nonprofit.id, - tag_master_id: tag_master_id, - list_name: list_name, - mailchimp_list_id: list_id, - created_at: el.created_at, - updated_at: el.updated_at - }.with_indifferent_access], - inserted_result: inserted_result, - deleted: [{"mailchimp_list_id" => 'with_list__mc_list'}], - deleted_result: "deleted correctly" + inserted_lists: [{ + id: el.id, + nonprofit_id: nonprofit.id, + tag_master_id: tag_master_id, + list_name: list_name, + mailchimp_list_id: list_id, + created_at: el.created_at, + updated_at: el.updated_at + }.with_indifferent_access], + inserted_result: inserted_result, + deleted: [{"mailchimp_list_id" => "with_list__mc_list"}], + deleted_result: "deleted correctly" } expect(result).to eq expected diff --git a/spec/lib/insert/insert_import_spec.rb b/spec/lib/insert/insert_import_spec.rb index b30b87232..e57774d5d 100644 --- a/spec/lib/insert/insert_import_spec.rb +++ b/spec/lib/insert/insert_import_spec.rb @@ -1,17 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -describe InsertImport do - - describe 'parsing' do - - let(:user) { create(:user)} +describe InsertImport do + describe "parsing" do + let(:user) { create(:user) } subject(:import_result) do import = InsertImport.from_csv( nonprofit_id: create(:fv_poverty).id, - user_email: user.email, + user_email: user.email, user_id: user.id, - file_uri: "#{ENV['PWD']}/spec/fixtures/test_import.csv", + file_uri: "#{ENV["PWD"]}/spec/fixtures/test_import.csv", header_matches: { "Date" => "donation.date", "Program" => "donation.designation", @@ -28,212 +26,210 @@ "Field Guy" => "custom_field", "Tag 1" => "tag", "Tag 2" => "tag" - }) - - + } + ) - Import.find(import['id']) + Import.find(import["id"]) end - it { expect{import_result}.to change{Supporter.count}.by(5)} - it { expect{import_result}.to change{Payment.count}.by(5)} + it { expect { import_result }.to change { Supporter.count }.by(5) } + it { expect { import_result }.to change { Payment.count }.by(5) } - describe 'import for user@example1.com' do - subject(:supporter) { + describe "import for user@example1.com" do + subject(:supporter) { import_result Supporter.find_by_email("user@example1.com") } - it do + it do is_expected.to have_attributes( - donations: + donations: a_collection_containing_exactly( - an_instance_of(Donation).and have_attributes(amount: 1000) + an_instance_of(Donation).and(have_attributes(amount: 1000)) ) ) end - it { + it { is_expected.to have_attributes( - address: 'P.O. Box 611', - city: 'Snead', - state_code: 'AL', - zip_code: '35952' + address: "P.O. Box 611", + city: "Snead", + state_code: "AL", + zip_code: "35952" ) } - describe 'primary_address' do + describe "primary_address" do subject { supporter.primary_address } - it do + it do is_expected.to have_attributes( - address: 'P.O. Box 611', - city: 'Snead', - state_code: 'AL', - zip_code: '35952' + address: "P.O. Box 611", + city: "Snead", + state_code: "AL", + zip_code: "35952" ) end end end - describe 'import for user2@example2.com' do - subject(:supporter) { + describe "import for user2@example2.com" do + subject(:supporter) { import_result Supporter.find_by_email("user2@example2.com") } - it do + it do is_expected.to have_attributes( - donations: + donations: a_collection_containing_exactly( - an_instance_of(Donation).and have_attributes(amount: 1040) + an_instance_of(Donation).and(have_attributes(amount: 1040)) ) ) end - it { + it { is_expected.to have_attributes( - address: 'P.O. Box 143', - city: 'Holly Pond', - state_code: 'AL', - zip_code: '35806' + address: "P.O. Box 143", + city: "Holly Pond", + state_code: "AL", + zip_code: "35806" ) } - describe 'primary_address' do + describe "primary_address" do subject { supporter.primary_address } - it do + it do is_expected.to have_attributes( - address: 'P.O. Box 143', - city: 'Holly Pond', - state_code: 'AL', - zip_code: '35806' + address: "P.O. Box 143", + city: "Holly Pond", + state_code: "AL", + zip_code: "35806" ) end end end - describe 'import for user5@example.com' do - subject(:supporter) { + describe "import for user5@example.com" do + subject(:supporter) { import_result Supporter.find_by_email("user5@example.com") } - it do + it do is_expected.to have_attributes( - donations: + donations: a_collection_containing_exactly( - an_instance_of(Donation).and have_attributes(amount: 0) + an_instance_of(Donation).and(have_attributes(amount: 0)) ) ) end - it { + it { is_expected.to have_attributes( address: nil, - city: 'Guntersville', - state_code: 'WI', - zip_code: '54915' + city: "Guntersville", + state_code: "WI", + zip_code: "54915" ) } - describe 'primary_address' do + describe "primary_address" do subject { supporter.primary_address } - it do + it do is_expected.to have_attributes( address: nil, - city: 'Guntersville', - state_code: 'WI', - zip_code: '54915' + city: "Guntersville", + state_code: "WI", + zip_code: "54915" ) end end end - - describe 'import for Bill Waddell' do - subject(:supporter) { + describe "import for Bill Waddell" do + subject(:supporter) { import_result Supporter.find_by_name("Bill Waddell") } - it do + it do is_expected.to have_attributes( - donations: + donations: a_collection_containing_exactly( - an_instance_of(Donation).and have_attributes(amount: 1000) + an_instance_of(Donation).and(have_attributes(amount: 1000)) ) ) end - it do + it do is_expected.to have_attributes( - name: 'Bill Waddell', - email: 'user@example.com', - address: '649 Finley Island Road', - city: 'Decatur', - state_code: 'AL', - zip_code: '35601' + name: "Bill Waddell", + email: "user@example.com", + address: "649 Finley Island Road", + city: "Decatur", + state_code: "AL", + zip_code: "35601" ) end - describe 'primary_address' do + describe "primary_address" do subject { supporter.primary_address } - it "will keep the address from the first supporter" do + it "will keep the address from the first supporter" do is_expected.to have_attributes( - address: '649 Finley Island Road', - city: 'Decatur', - state_code: 'AL', - zip_code: '35601' + address: "649 Finley Island Road", + city: "Decatur", + state_code: "AL", + zip_code: "35601" ) end end end - describe 'import for Bubba Thurmond' do - subject(:supporter) { + describe "import for Bubba Thurmond" do + subject(:supporter) { import_result Supporter.find_by_name("Bubba Thurmond") } - it do + it do is_expected.to have_attributes( - donations: + donations: a_collection_containing_exactly( - an_instance_of(Donation).and have_attributes(amount: 1000) + an_instance_of(Donation).and(have_attributes(amount: 1000)) ) ) end - it do + it do is_expected.to have_attributes( - name: 'Bubba Thurmond', - email: 'user@example.com', - address: '3370 Alabama Highway 69', - city: 'Guntersville', - state_code: 'AL', - zip_code: '35976' + name: "Bubba Thurmond", + email: "user@example.com", + address: "3370 Alabama Highway 69", + city: "Guntersville", + state_code: "AL", + zip_code: "35976" ) end - describe 'primary_address' do + describe "primary_address" do subject { supporter.primary_address } - it "will keep the address from the first supporter" do + it "will keep the address from the first supporter" do is_expected.to have_attributes( - address: '3370 Alabama Highway 69', - city: 'Guntersville', - state_code: 'AL', - zip_code: '35976' + address: "3370 Alabama Highway 69", + city: "Guntersville", + state_code: "AL", + zip_code: "35976" ) end end diff --git a/spec/lib/insert/insert_payout_spec.rb b/spec/lib/insert/insert_payout_spec.rb index 2a8c091b8..e9902b994 100644 --- a/spec/lib/insert/insert_payout_spec.rb +++ b/spec/lib/insert/insert_payout_spec.rb @@ -1,101 +1,97 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'support/payments_for_a_payout' +require "rails_helper" +require "support/payments_for_a_payout" describe InsertPayout do - let(:bank_name) {'CHASE *1234'} - let(:supporter) {force_create(:supporter)} - let(:user_email) {'uzr@example.com'} - let(:user_ip) {'8.8.8.8'} - - describe '.with_stripe' do - describe 'param validation' do - it 'basic param validation' do - expect {InsertPayout.with_stripe(nil, nil, nil)}.to(raise_error {|error| + let(:bank_name) { "CHASE *1234" } + let(:supporter) { force_create(:supporter) } + let(:user_email) { "uzr@example.com" } + let(:user_ip) { "8.8.8.8" } + + describe ".with_stripe" do + describe "param validation" do + it "basic param validation" do + expect { InsertPayout.with_stripe(nil, nil, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {key: :np_id, name: :required}, - {key: :np_id, name: :is_integer}, - {key: :stripe_account_id, name: :required}, - {key: :stripe_account_id, name: :not_blank}, - {key: :email, name: :required}, - {key: :email, name: :not_blank}, - {key: :user_ip, name: :required}, - {key: :user_ip, name: :not_blank}, - {key: :bank_name, name: :required}, - {key: :bank_name, name: :not_blank}, + {key: :np_id, name: :required}, + {key: :np_id, name: :is_integer}, + {key: :stripe_account_id, name: :required}, + {key: :stripe_account_id, name: :not_blank}, + {key: :email, name: :required}, + {key: :email, name: :not_blank}, + {key: :user_ip, name: :required}, + {key: :user_ip, name: :not_blank}, + {key: :bank_name, name: :required}, + {key: :bank_name, name: :not_blank} ]) }) - end - it 'validates nonprofit' do - expect {InsertPayout.with_stripe(666, {:stripe_account_id => 'valid', :email => 'valid', user_ip: 'valid', bank_name: 'valid'}, nil)}.to(raise_error {|error| + it "validates nonprofit" do + expect { InsertPayout.with_stripe(666, {stripe_account_id: "valid", email: "valid", user_ip: "valid", bank_name: "valid"}, nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :np_id}]) }) end - it 'errors when the nonprofit is deactivated' do - np = force_create(:nonprofit, name: 'np') + it "errors when the nonprofit is deactivated" do + np = force_create(:nonprofit, name: "np") force_create(:nonprofit_deactivation, nonprofit: np, deactivated: true) - expect { InsertPayout.with_stripe(np.id, {:stripe_account_id => 'valid', :email => 'valid', user_ip: 'valid', bank_name: 'valid'}, nil) }.to(raise_error { |error| + expect { InsertPayout.with_stripe(np.id, {stripe_account_id: "valid", email: "valid", user_ip: "valid", bank_name: "valid"}, nil) }.to(raise_error { |error| expect(error).to be_a ArgumentError expect(error.message).to eq "Sorry, this account has been deactivated." }) end - it 'errors when the nonprofit cant make a payout' do - np = force_create(:nonprofit, name: 'np', vetted: false) - expect { InsertPayout.with_stripe(np.id, {:stripe_account_id => 'valid', :email => 'valid', user_ip: 'valid', bank_name: 'valid'}, nil) }.to(raise_error { |error| + it "errors when the nonprofit cant make a payout" do + np = force_create(:nonprofit, name: "np", vetted: false) + expect { InsertPayout.with_stripe(np.id, {stripe_account_id: "valid", email: "valid", user_ip: "valid", bank_name: "valid"}, nil) }.to(raise_error { |error| expect(error).to be_a ArgumentError expect(error.message).to eq "Sorry, this account can't make payouts right now." }) end end - context 'when valid' do - + context "when valid" do around(:each) do |example| - Timecop.freeze(2020, 5, 5) do - StripeMockHelper.mock do + Timecop.freeze(2020, 5, 5) do + StripeMockHelper.mock do example.run end end end - context 'no charges to payout' do - include_context 'payments for a payout' do - let(:nonprofit) {force_create(:nonprofit, :stripe_account_id => Stripe::Account.create()['id'], vetted: true)} - let(:supporter) {force_create(:supporter, nonprofit: nonprofit)} + context "no charges to payout" do + include_context "payments for a payout" do + let(:nonprofit) { force_create(:nonprofit, stripe_account_id: Stripe::Account.create["id"], vetted: true) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } end - + let!(:ba) do - ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token(), name: bank_name}) + ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token, name: bank_name}) ba.pending_verification = false ba.save! ba end - - let!(:stripe_account) do + + let!(:stripe_account) do force_create(:stripe_account, stripe_account_id: nonprofit.stripe_account_id, payouts_enabled: true) end - - it 'handles no charges to payout' do - #we have a deactivation record but no deactivate set + it "handles no charges to payout" do + # we have a deactivation record but no deactivate set force_create(:nonprofit_deactivation, nonprofit: nonprofit) - expect {InsertPayout.with_stripe(nonprofit.id, {:stripe_account_id => 'valid', :email => 'valid', user_ip: 'valid', bank_name: 'valid'}, nil)}.to(raise_error {|error| + expect { InsertPayout.with_stripe(nonprofit.id, {stripe_account_id: "valid", email: "valid", user_ip: "valid", bank_name: "valid"}, nil) }.to(raise_error { |error| expect(error).to be_a ArgumentError expect(error.message).to eq "No payments are available for disbursal on this account." }) end end - - let(:user) {force_create(:user)} - # Test one basic charge, one charge with a partial refund, and one charge with a full refund + let(:user) { force_create(:user) } + # Test one basic charge, one charge with a partial refund, and one charge with a full refund # refunded payment # disputed payment @@ -106,58 +102,56 @@ # Already paid out dispute # already paid out refund - context 'no date provided' do - include_context 'payments for a payout' do - let(:nonprofit) {force_create(:nonprofit, :stripe_account_id => Stripe::Account.create()['id'], vetted: true)} - let(:supporter) {force_create(:supporter, nonprofit: nonprofit)} + context "no date provided" do + include_context "payments for a payout" do + let(:nonprofit) { force_create(:nonprofit, stripe_account_id: Stripe::Account.create["id"], vetted: true) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } end let!(:ba) do - ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token(), name: bank_name}) + ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token, name: bank_name}) ba.pending_verification = false ba.save! ba - end - let!(:stripe_account) do + let!(:stripe_account) do force_create(:stripe_account, stripe_account_id: nonprofit.stripe_account_id, payouts_enabled: true) end - let!(:expected_payments) { available_payments_yesterday} - let(:expected_totals) {eb_yesterday.stats.except(:pending_gross, :pending_net)} - - it 'works without a date provided' do + let!(:expected_payments) { available_payments_yesterday } + let(:expected_totals) { eb_yesterday.stats.except(:pending_gross, :pending_net) } + + it "works without a date provided" do stripe_transfer_id = nil expect(Stripe::Payout).to receive(:create).with({amount: expected_totals[:net_amount], - currency: 'usd' - }, { - stripe_account: nonprofit.stripe_account_id}) - .and_wrap_original {|m, *args| - args[0]['status'] = 'pending' - i = m.call(*args) - stripe_transfer_id = i['id']; - i - } + currency: "usd"}, { + stripe_account: nonprofit.stripe_account_id + }) + .and_wrap_original { |m, *args| + args[0]["status"] = "pending" + i = m.call(*args) + stripe_transfer_id = i["id"] + i + } entities_yesterday result = InsertPayout.with_stripe(nonprofit.id, {stripe_account_id: nonprofit.stripe_account_id, email: user_email, user_ip: user_ip, - bank_name: bank_name - }) + bank_name: bank_name}) expected_result = { - net_amount: expected_totals[:net_amount], - nonprofit_id: nonprofit.id, - status: 'pending', - fee_total: expected_totals[:fee_total], - gross_amount: expected_totals[:gross_amount], - email: user_email, - count: expected_totals[:count], - stripe_transfer_id: stripe_transfer_id, - user_ip: user_ip, - ach_fee: 0, - bank_name: bank_name, - updated_at: Time.now, - created_at: Time.now + net_amount: expected_totals[:net_amount], + nonprofit_id: nonprofit.id, + status: "pending", + fee_total: expected_totals[:fee_total], + gross_amount: expected_totals[:gross_amount], + email: user_email, + count: expected_totals[:count], + stripe_transfer_id: stripe_transfer_id, + user_ip: user_ip, + ach_fee: 0, + bank_name: bank_name, + updated_at: Time.now, + created_at: Time.now }.with_indifferent_access expect(Payout.count).to eq 1 resulted_payout = Payout.first @@ -166,11 +160,11 @@ empty_db_attributes = {manual: nil, scheduled: nil, failure_message: nil} expect(resulted_payout).to have_attributes(expected_result.merge(id: resulted_payout.id).merge(empty_db_attributes)) expect(resulted_payout.houid).to match_houid(:pyout) - expect(resulted_payout.payments.pluck('payments.id')).to match_array(expected_payments.map{|i| i.id}) + expect(resulted_payout.payments.pluck("payments.id")).to match_array(expected_payments.map { |i| i.id }) end - it 'fails properly when Stripe payout call fails' do - #we have a deactivation record but deactivate set to false + it "fails properly when Stripe payout call fails" do + # we have a deactivation record but deactivate set to false force_create(:nonprofit_deactivation, nonprofit: nonprofit, deactivated: false) StripeMockHelper.prepare_error(Stripe::StripeError.new("Payout failed"), :new_payout) @@ -179,166 +173,160 @@ result = InsertPayout.with_stripe(nonprofit.id, {stripe_account_id: nonprofit.stripe_account_id, email: user_email, user_ip: user_ip, - bank_name: bank_name - }) + bank_name: bank_name}) expected_result = { - net_amount: expected_totals[:net_amount], - nonprofit_id: nonprofit.id, - status: 'failed', - fee_total: expected_totals[:fee_total], - gross_amount: expected_totals[:gross_amount], - email: user_email, - count: expected_totals[:count], - stripe_transfer_id: nil, - user_ip: user_ip, - ach_fee: 0, - bank_name: bank_name, - updated_at: Time.now, - created_at: Time.now + net_amount: expected_totals[:net_amount], + nonprofit_id: nonprofit.id, + status: "failed", + fee_total: expected_totals[:fee_total], + gross_amount: expected_totals[:gross_amount], + email: user_email, + count: expected_totals[:count], + stripe_transfer_id: nil, + user_ip: user_ip, + ach_fee: 0, + bank_name: bank_name, + updated_at: Time.now, + created_at: Time.now }.with_indifferent_access expect(Payout.count).to eq 1 resulted_payout = Payout.first expect(result.with_indifferent_access).to eq expected_result.merge(id: resulted_payout.id, houid: resulted_payout.houid) - empty_db_attributes = {manual: nil, scheduled: nil, failure_message: 'Payout failed', } + empty_db_attributes = {manual: nil, scheduled: nil, failure_message: "Payout failed"} expect(resulted_payout).to have_attributes(expected_result.merge(id: resulted_payout.id).merge(empty_db_attributes)) - expect(eb_yesterday.available_payments.map{|i| i.id}).to match_array(expected_payments.map{|i| i.id}) + expect(eb_yesterday.available_payments.map { |i| i.id }).to match_array(expected_payments.map { |i| i.id }) # validate payment payout records expect(resulted_payout.payments.count).to eq 0 end end - context 'previous date provided' do - include_context 'payments for a payout' do - let(:nonprofit) {force_create(:nonprofit, :stripe_account_id => Stripe::Account.create()['id'], vetted: true)} - + context "previous date provided" do + include_context "payments for a payout" do + let(:nonprofit) { force_create(:nonprofit, stripe_account_id: Stripe::Account.create["id"], vetted: true) } end let!(:ba) do - ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token(), name: bank_name}) + ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token, name: bank_name}) ba.pending_verification = false ba.save! ba end - let!(:stripe_account) do + let!(:stripe_account) do force_create(:stripe_account, stripe_account_id: nonprofit.stripe_account_id, payouts_enabled: true) end - before(:each) do + before(:each) do entities_yesterday entities_two_days_ago end - let!(:expected_payments) { available_payments_two_days_ago} - let(:expected_totals) {eb_two_days_ago.stats.except(:pending_total)} + let!(:expected_payments) { available_payments_two_days_ago } + let(:expected_totals) { eb_two_days_ago.stats.except(:pending_total) } - it 'works with date provided' do + it "works with date provided" do stripe_transfer_id = nil expect(Stripe::Payout).to receive(:create).with({amount: expected_totals[:net_amount], - currency: 'usd', - }, { - stripe_account: nonprofit.stripe_account_id}) - .and_wrap_original {|m, *args| - args[0]['status'] = 'pending' - i = m.call(*args) - stripe_transfer_id = i['id']; - i - } + currency: "usd"}, { + stripe_account: nonprofit.stripe_account_id + }) + .and_wrap_original { |m, *args| + args[0]["status"] = "pending" + i = m.call(*args) + stripe_transfer_id = i["id"] + i + } result = InsertPayout.with_stripe(nonprofit.id, {stripe_account_id: nonprofit.stripe_account_id, email: user_email, user_ip: user_ip, - bank_name: bank_name - }, {date: Time.now - 1.day}) + bank_name: bank_name}, {date: Time.now - 1.day}) expected_result = { - net_amount: expected_totals[:net_amount], - nonprofit_id: nonprofit.id, - status: 'pending', - fee_total: expected_totals[:fee_total], - gross_amount: expected_totals[:gross_amount], - email: user_email, - count: expected_totals[:count], - stripe_transfer_id: stripe_transfer_id, - user_ip: user_ip, - ach_fee: 0, - bank_name: bank_name, - updated_at: Time.now, - created_at: Time.now + net_amount: expected_totals[:net_amount], + nonprofit_id: nonprofit.id, + status: "pending", + fee_total: expected_totals[:fee_total], + gross_amount: expected_totals[:gross_amount], + email: user_email, + count: expected_totals[:count], + stripe_transfer_id: stripe_transfer_id, + user_ip: user_ip, + ach_fee: 0, + bank_name: bank_name, + updated_at: Time.now, + created_at: Time.now }.with_indifferent_access expect(Payout.count).to eq 1 resulted_payout = Payout.first expect(result.with_indifferent_access).to eq expected_result.merge(id: resulted_payout.id, houid: resulted_payout.houid) empty_db_attributes = {manual: nil, scheduled: nil, failure_message: nil} - + expect(resulted_payout).to have_attributes(expected_result.merge(id: resulted_payout.id).merge(empty_db_attributes)) expect(resulted_payout.houid).to match_houid(:pyout) - expect(resulted_payout.payments.pluck('payments.id')).to match_array(expected_payments.map{|i| i.id}) + expect(resulted_payout.payments.pluck("payments.id")).to match_array(expected_payments.map { |i| i.id }) end - it 'fails properly when Stripe payout call fails' do + it "fails properly when Stripe payout call fails" do StripeMockHelper.prepare_error(Stripe::StripeError.new("Payout failed"), :new_payout) result = InsertPayout.with_stripe(nonprofit.id, {stripe_account_id: nonprofit.stripe_account_id, email: user_email, user_ip: user_ip, - bank_name: bank_name - }, {date: Time.now - 1.day}) + bank_name: bank_name}, {date: Time.now - 1.day}) expected_result = { - net_amount: expected_totals[:net_amount], - nonprofit_id: nonprofit.id, - status: 'failed', - fee_total: expected_totals[:fee_total], - gross_amount: expected_totals[:gross_amount], - email: user_email, - count: expected_totals[:count], - stripe_transfer_id: nil, - user_ip: user_ip, - ach_fee: 0, - bank_name: bank_name, - updated_at: Time.now, - created_at: Time.now + net_amount: expected_totals[:net_amount], + nonprofit_id: nonprofit.id, + status: "failed", + fee_total: expected_totals[:fee_total], + gross_amount: expected_totals[:gross_amount], + email: user_email, + count: expected_totals[:count], + stripe_transfer_id: nil, + user_ip: user_ip, + ach_fee: 0, + bank_name: bank_name, + updated_at: Time.now, + created_at: Time.now }.with_indifferent_access expect(Payout.count).to eq 1 resulted_payout = Payout.first expect(result.with_indifferent_access).to eq expected_result.merge(id: resulted_payout.id, houid: resulted_payout.houid) - empty_db_attributes = {manual: nil, scheduled: nil, failure_message: 'Payout failed', } + empty_db_attributes = {manual: nil, scheduled: nil, failure_message: "Payout failed"} expect(resulted_payout).to have_attributes(expected_result.merge(id: resulted_payout.id).merge(empty_db_attributes)) expect(resulted_payout.houid).to match_houid(:pyout) - expect(eb_two_days_ago.available_payments.map{|i| i.id}).to match_array(expected_payments.map{|i| i.id}) + expect(eb_two_days_ago.available_payments.map { |i| i.id }).to match_array(expected_payments.map { |i| i.id }) # validate payment payout records expect(resulted_payout.payments.count).to eq 0 end - it 'creates an associated payout.created object event with the correct fields' do + it "creates an associated payout.created object event with the correct fields" do result = InsertPayout.with_stripe(nonprofit.id, {stripe_account_id: nonprofit.stripe_account_id, email: user_email, user_ip: user_ip, - bank_name: bank_name - }, {date: Time.now - 1.day}) - resulting_payout = Payout.find(result['id']) + bank_name: bank_name}, {date: Time.now - 1.day}) + resulting_payout = Payout.find(result["id"]) - expect(resulting_payout.object_events.last.event_type).to eq 'payout.created' + expect(resulting_payout.object_events.last.event_type).to eq "payout.created" expect( resulting_payout.object_events.last.object_json.keys - ).to contain_exactly('id', 'data', 'type', 'object', 'created') + ).to contain_exactly("id", "data", "type", "object", "created") expect( - resulting_payout.object_events.last.object_json['data']['object'].keys - ).to contain_exactly('id', 'object', 'status', 'created', 'net_amount') + resulting_payout.object_events.last.object_json["data"]["object"].keys + ).to contain_exactly("id", "object", "status", "created", "net_amount") end end end end end - diff --git a/spec/lib/insert/insert_recurring_donation_spec.rb b/spec/lib/insert/insert_recurring_donation_spec.rb index 144b9986e..f18f87ec1 100644 --- a/spec/lib/insert/insert_recurring_donation_spec.rb +++ b/spec/lib/insert/insert_recurring_donation_spec.rb @@ -1,116 +1,117 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertRecurringDonation do - describe '.with_stripe' do + describe ".with_stripe" do include_context :shared_rd_donation_value_context - it 'does basic validation' do - validation_basic_validation {InsertRecurringDonation.with_stripe({designation: 34124, dedication: 35141, event_id: "bad", campaign_id: 'bad'})} + it "does basic validation" do + validation_basic_validation { InsertRecurringDonation.with_stripe({designation: 34124, dedication: 35141, event_id: "bad", campaign_id: "bad"}) } end - it 'does recurring donation validation' do - expect {InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid, - recurring_donation: {interval: "not number", start_date: "not_date", time_unit: 4, paydate: "faf"})}.to raise_error {|e| - expect(e).to be_a ParamValidation::ValidationError - expect_validation_errors(e.data, [ - {key: :interval, name: :is_integer}, - {key: :start_date, name: :can_be_date}, - {key: :time_unit, name: :included_in}, - {key: :paydate, name: :is_integer} - ]) - - } + it "does recurring donation validation" do + expect { + InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid, + recurring_donation: {interval: "not number", start_date: "not_date", time_unit: 4, paydate: "faf"}) + }.to raise_error { |e| + expect(e).to be_a ParamValidation::ValidationError + expect_validation_errors(e.data, [ + {key: :interval, name: :is_integer}, + {key: :start_date, name: :can_be_date}, + {key: :time_unit, name: :included_in}, + {key: :paydate, name: :is_integer} + ]) + } end - it 'does paydate validation min' do - expect {InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid, - recurring_donation: {paydate: "0"})}.to raise_error {|e| - expect(e).to be_a ParamValidation::ValidationError - expect_validation_errors(e.data, [ - {key: :paydate, name: :min} - ]) - - } + it "does paydate validation min" do + expect { + InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid, + recurring_donation: {paydate: "0"}) + }.to raise_error { |e| + expect(e).to be_a ParamValidation::ValidationError + expect_validation_errors(e.data, [ + {key: :paydate, name: :min} + ]) + } end - it 'does paydate validation max' do - expect {InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid, - recurring_donation: {paydate: "29"})}.to raise_error {|e| - expect(e).to be_a ParamValidation::ValidationError - expect_validation_errors(e.data, [ - {key: :paydate, name: :max} - ]) - - } + it "does paydate validation max" do + expect { + InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid, + recurring_donation: {paydate: "29"}) + }.to raise_error { |e| + expect(e).to be_a ParamValidation::ValidationError + expect_validation_errors(e.data, [ + {key: :paydate, name: :max} + ]) + } end - it 'errors out if token is invalid' do - validation_invalid_token {InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid)} + it "errors out if token is invalid" do + validation_invalid_token { InsertRecurringDonation.with_stripe(amount: 1, nonprofit_id: 1, supporter_id: 1, token: fake_uuid) } end - it 'errors out if token is unauthorized' do - validation_unauthorized {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: 1, supporter_id: 1, token: fake_uuid)} + it "errors out if token is unauthorized" do + validation_unauthorized { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: 1, supporter_id: 1, token: fake_uuid) } end - it 'errors out if token is expired' do - validation_expired {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: 1, supporter_id: 1, token: fake_uuid)} + it "errors out if token is expired" do + validation_expired { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: 1, supporter_id: 1, token: fake_uuid) } end - - describe 'errors during find if' do - it 'supporter is invalid' do - find_error_supporter {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: 55555, token: source_token.token)} + describe "errors during find if" do + it "supporter is invalid" do + find_error_supporter { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: 55555, token: source_token.token) } end - it 'nonprofit is invalid' do - find_error_nonprofit {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: 55555, supporter_id: supporter.id, token: source_token.token)} + it "nonprofit is invalid" do + find_error_nonprofit { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: 55555, supporter_id: supporter.id, token: source_token.token) } end - it 'campaign is invalid' do - find_error_campaign {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: 5555)} + it "campaign is invalid" do + find_error_campaign { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: 5555) } end - it 'event is invalid' do - find_error_event {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: 5555)} + it "event is invalid" do + find_error_event { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: 5555) } end - it 'profile is invalid' do - find_error_profile {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: 5555)} + it "profile is invalid" do + find_error_profile { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: 5555) } end end - describe 'errors during relationship comparison if' do - - it 'event is deleted' do + describe "errors during relationship comparison if" do + it "event is deleted" do validation_event_deleted { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id) } end - it 'campaign is deleted' do + it "campaign is deleted" do validation_campaign_deleted { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id) } end - it 'supporter is deleted' do - validation_supporter_deleted {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token)} + it "supporter is deleted" do + validation_supporter_deleted { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) } end - it 'supporter doesnt belong to nonprofit' do - validation_supporter_not_with_nonprofit {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: other_nonprofit_supporter.id, token: source_token.token)} + it "supporter doesnt belong to nonprofit" do + validation_supporter_not_with_nonprofit { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: other_nonprofit_supporter.id, token: source_token.token) } end - it 'campaign doesnt belong to nonprofit' do - validation_campaign_not_with_nonprofit {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: other_campaign.id)} + it "campaign doesnt belong to nonprofit" do + validation_campaign_not_with_nonprofit { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: other_campaign.id) } end - it 'event doesnt belong to nonprofit' do - validation_event_not_with_nonprofit {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: other_event.id)} + it "event doesnt belong to nonprofit" do + validation_event_not_with_nonprofit { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: other_event.id) } end - it 'card doesnt belong to supporter' do - validation_card_not_with_supporter {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: other_source_token.token)} + it "card doesnt belong to supporter" do + validation_card_not_with_supporter { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: other_source_token.token) } end - it 'if nonprofit is unvetted' do + it "if nonprofit is unvetted" do find_error_nonprofit do nonprofit.update(vetted: false) InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: other_source_token.token) @@ -118,51 +119,47 @@ end end - - it 'charge returns failed' do - handle_charge_failed {InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token)} + it "charge returns failed" do + handle_charge_failed { InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token) } end - describe 'success' do - before(:each){ + describe "success" do + before(:each) { allow(SecureRandom).to receive(:uuid).and_return(default_edit_token) } - describe 'charge happens' do + describe "charge happens" do before(:each) { before_each_success } - it 'process event donation' do - process_event_donation(recurring_donation: {paydate: nil, interval: 1, time_unit: 'year', start_date: Time.current.beginning_of_day}) { - - result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', recurring_donation: {time_unit: 'year'}, fee_covered: false) + it "process event donation" do + process_event_donation(recurring_donation: {paydate: nil, interval: 1, time_unit: "year", start_date: Time.current.beginning_of_day}) { + result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation", recurring_donation: {time_unit: "year"}, fee_covered: false) - p = Payment.find(result['payment']['id']) - rd = RecurringDonation.find(result['recurring_donation']['id']) + p = Payment.find(result["payment"]["id"]) + rd = RecurringDonation.find(result["recurring_donation"]["id"]) expect(p.misc_payment_info.fee_covered).to eq false expect(rd.misc_recurring_donation_info.fee_covered).to eq false result } end - it 'process campaign donation' do - process_campaign_donation(recurring_donation: {paydate: nil, interval: 2, time_unit: 'month', start_date: Time.current.beginning_of_day}) { - result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', recurring_donation: {interval: 2}, fee_covered: true) + it "process campaign donation" do + process_campaign_donation(recurring_donation: {paydate: nil, interval: 2, time_unit: "month", start_date: Time.current.beginning_of_day}) { + result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, campaign_id: campaign.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation", recurring_donation: {interval: 2}, fee_covered: true) - - p = Payment.find(result['payment']['id']) - rd = RecurringDonation.find(result['recurring_donation']['id']) - expect(p.misc_payment_info.fee_covered).to eq true - expect(rd.misc_recurring_donation_info.fee_covered).to eq true - result - - } + p = Payment.find(result["payment"]["id"]) + rd = RecurringDonation.find(result["recurring_donation"]["id"]) + expect(p.misc_payment_info.fee_covered).to eq true + expect(rd.misc_recurring_donation_info.fee_covered).to eq true + result + } end - it 'processes general donation with no recurring donation hash' do - process_general_donation(recurring_donation: {paydate: Time.now.day, interval: 1, time_unit: 'month', start_date: Time.now.beginning_of_day}) { - result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: Time.now.to_s, dedication: 'dedication', designation: 'designation') - p = Payment.find(result['payment']['id']) - rd = RecurringDonation.find(result['recurring_donation']['id']) + it "processes general donation with no recurring donation hash" do + process_general_donation(recurring_donation: {paydate: Time.now.day, interval: 1, time_unit: "month", start_date: Time.now.beginning_of_day}) { + result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: Time.now.to_s, dedication: "dedication", designation: "designation") + p = Payment.find(result["payment"]["id"]) + rd = RecurringDonation.find(result["recurring_donation"]["id"]) expect(p.misc_payment_info.fee_covered).to be_nil expect(rd.misc_recurring_donation_info.fee_covered).to be_nil result @@ -170,39 +167,37 @@ end end - describe 'future charge' do + describe "future charge" do before(:each) { before_each_success(false) } - it 'processes general donation' do - process_general_donation(expect_payment: false, expect_charge: false, recurring_donation: {paydate: (Time.now + 5.days).day, interval: 1, time_unit: 'month', start_date: (Time.now + 5.days).beginning_of_day}) { - result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', - recurring_donation: { start_date: (Time.now + 5.days).to_s}) - - rd = RecurringDonation.find(result['recurring_donation']['id']) + it "processes general donation" do + process_general_donation(expect_payment: false, expect_charge: false, recurring_donation: {paydate: (Time.now + 5.days).day, interval: 1, time_unit: "month", start_date: (Time.now + 5.days).beginning_of_day}) { + result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation", + recurring_donation: {start_date: (Time.now + 5.days).to_s}) + + rd = RecurringDonation.find(result["recurring_donation"]["id"]) expect(rd.misc_recurring_donation_info.fee_covered).to be_nil result } end - it 'includes fee covering' do - process_general_donation(expect_payment: false, expect_charge: false, recurring_donation: {paydate: (Time.now + 5.days).day, interval: 1, time_unit: 'month', start_date: (Time.now + 5.days).beginning_of_day}) { - result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: 'dedication', designation: 'designation', recurring_donation: { start_date: (Time.now + 5.days).to_s}, fee_covered: true) + it "includes fee covering" do + process_general_donation(expect_payment: false, expect_charge: false, recurring_donation: {paydate: (Time.now + 5.days).day, interval: 1, time_unit: "month", start_date: (Time.now + 5.days).beginning_of_day}) { + result = InsertRecurringDonation.with_stripe(amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, profile_id: profile.id, date: (Time.now + 1.day).to_s, dedication: "dedication", designation: "designation", recurring_donation: {start_date: (Time.now + 5.days).to_s}, fee_covered: true) - rd = RecurringDonation.find(result['recurring_donation']['id']) + rd = RecurringDonation.find(result["recurring_donation"]["id"]) expect(rd.misc_recurring_donation_info.fee_covered).to eq true result } end end end - end - - describe '.convert_donation_to_recurring_donation' do - describe 'wonderful testing Eric' do + describe ".convert_donation_to_recurring_donation" do + describe "wonderful testing Eric" do around(:each) do |ex| StripeMockHelper.mock do Timecop.freeze(2020, 4, 29) do @@ -210,65 +205,58 @@ end end end - let(:nonprofit) {force_create(:nonprofit, :state_code_slug => "wi", :city_slug => 'city', slug: "sluggster")} - let(:profile) {force_create(:profile, :user => force_create(:user))} - let(:supporter) {force_create(:supporter, :nonprofit => nonprofit)} - let(:card) {force_create(:card, holder: supporter)} - let(:campaign) {force_create(:campaign, :profile => profile, :nonprofit => nonprofit)} - let(:event) {force_create(:event, :profile => profile, :nonprofit => nonprofit)} - let!(:donation) {force_create(:donation, :nonprofit => nonprofit, :supporter => supporter, :amount => 4000, card: card, campaign: campaign, event: event)} - let!(:payment) {force_create(:payment, :donation => donation, :kind => "Donation")} - - - it 'param validation' do - expect {InsertRecurringDonation.convert_donation_to_recurring_donation(nil)}.to(raise_error {|error| + let(:nonprofit) { force_create(:nonprofit, state_code_slug: "wi", city_slug: "city", slug: "sluggster") } + let(:profile) { force_create(:profile, user: force_create(:user)) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } + let(:card) { force_create(:card, holder: supporter) } + let(:campaign) { force_create(:campaign, profile: profile, nonprofit: nonprofit) } + let(:event) { force_create(:event, profile: profile, nonprofit: nonprofit) } + let!(:donation) { force_create(:donation, nonprofit: nonprofit, supporter: supporter, amount: 4000, card: card, campaign: campaign, event: event) } + let!(:payment) { force_create(:payment, donation: donation, kind: "Donation") } + + it "param validation" do + expect { InsertRecurringDonation.convert_donation_to_recurring_donation(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :donation_id, name: :required}, {key: :donation_id, name: :is_integer}]) - }) end - it 'rejects invalid donation' do - expect {InsertRecurringDonation.convert_donation_to_recurring_donation(5555)}.to(raise_error {|error| + it "rejects invalid donation" do + expect { InsertRecurringDonation.convert_donation_to_recurring_donation(5555) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :donation_id}]) - }) end - it 'accepts proper information' do - - + it "accepts proper information" do Timecop.freeze(2020, 5, 4) do rd = InsertRecurringDonation.convert_donation_to_recurring_donation(donation.id) # this needs some serious improvement - expected_rd = { id: rd.id, - donation_id: donation.id, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - updated_at: Time.now, - created_at: Time.now, - active:true, - n_failures: 0, - interval: 1, - time_unit: 'month', - start_date: donation.created_at.beginning_of_day, - paydate: 28, - profile_id: nil, - cancelled_at:nil, - cancelled_by:nil, - amount: 4000, - anonymous: false, - card_id: nil, - campaign_id:nil, - failure_message: nil, - end_date: nil, - email: nil, - origin_url: nil - - }.with_indifferent_access - - expect(rd.attributes.except('edit_token')).to eq(expected_rd) + expected_rd = {id: rd.id, + donation_id: donation.id, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + updated_at: Time.now, + created_at: Time.now, + active: true, + n_failures: 0, + interval: 1, + time_unit: "month", + start_date: donation.created_at.beginning_of_day, + paydate: 28, + profile_id: nil, + cancelled_at: nil, + cancelled_by: nil, + amount: 4000, + anonymous: false, + card_id: nil, + campaign_id: nil, + failure_message: nil, + end_date: nil, + email: nil, + origin_url: nil}.with_indifferent_access + + expect(rd.attributes.except("edit_token")).to eq(expected_rd) expect(rd.edit_token).to_not be_falsey @@ -278,7 +266,7 @@ end end - describe 'test for earlier in the month' do + describe "test for earlier in the month" do around(:each) do |ex| StripeMockHelper.mock do Timecop.freeze(2020, 4, 5) do @@ -286,45 +274,44 @@ end end end - let(:nonprofit) {force_create(:nonprofit, :state_code_slug => "wi", :city_slug => 'city', slug: "sluggster")} - let(:profile) {force_create(:profile, :user => force_create(:user))} - let(:supporter) {force_create(:supporter, :nonprofit => nonprofit)} - let(:card) {force_create(:card, holder: supporter)} - let(:campaign) {force_create(:campaign, :profile => profile, :nonprofit => nonprofit)} - let(:event) {force_create(:event, :profile => profile, :nonprofit => nonprofit)} - - let!(:donation) {force_create(:donation, :nonprofit => nonprofit, :supporter => supporter, :amount => 4000, card: card, campaign: campaign, event: event)} - let!(:payment) {force_create(:payment, :donation => donation, :kind => "Donation")} - it 'works when the date is earlier in the month' do + let(:nonprofit) { force_create(:nonprofit, state_code_slug: "wi", city_slug: "city", slug: "sluggster") } + let(:profile) { force_create(:profile, user: force_create(:user)) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } + let(:card) { force_create(:card, holder: supporter) } + let(:campaign) { force_create(:campaign, profile: profile, nonprofit: nonprofit) } + let(:event) { force_create(:event, profile: profile, nonprofit: nonprofit) } + + let!(:donation) { force_create(:donation, nonprofit: nonprofit, supporter: supporter, amount: 4000, card: card, campaign: campaign, event: event) } + let!(:payment) { force_create(:payment, donation: donation, kind: "Donation") } + it "works when the date is earlier in the month" do Timecop.freeze(2020, 4, 29) do rd = InsertRecurringDonation.convert_donation_to_recurring_donation(donation.id) # this needs some serious improvement - expected_rd = { id: rd.id, - donation_id: donation.id, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - updated_at: Time.now, - created_at: Time.now, - active:true, - n_failures: 0, - interval: 1, - time_unit: 'month', - start_date: donation.created_at.beginning_of_day, - paydate: 5, - profile_id: nil, - cancelled_at:nil, - cancelled_by:nil, - amount: 4000, - anonymous: false, - card_id: nil, - campaign_id:nil, - failure_message: nil, - end_date: nil, - email: nil, - origin_url: nil - }.with_indifferent_access - expect(rd.attributes.except('edit_token')).to eq(expected_rd) + expected_rd = {id: rd.id, + donation_id: donation.id, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + updated_at: Time.now, + created_at: Time.now, + active: true, + n_failures: 0, + interval: 1, + time_unit: "month", + start_date: donation.created_at.beginning_of_day, + paydate: 5, + profile_id: nil, + cancelled_at: nil, + cancelled_by: nil, + amount: 4000, + anonymous: false, + card_id: nil, + campaign_id: nil, + failure_message: nil, + end_date: nil, + email: nil, + origin_url: nil}.with_indifferent_access + expect(rd.attributes.except("edit_token")).to eq(expected_rd) expect(rd.donation.recurring).to eq true expect(rd.donation.payment.kind).to eq "RecurringDonation" diff --git a/spec/lib/insert/insert_refunds_spec.rb b/spec/lib/insert/insert_refunds_spec.rb index 5f48b1131..1decfa910 100644 --- a/spec/lib/insert/insert_refunds_spec.rb +++ b/spec/lib/insert/insert_refunds_spec.rb @@ -1,14 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertRefunds do include_context :shared_donation_charge_context - describe ".modern_refund" do - + describe ".modern_refund" do context :modern_refund_shared do include_context "common fee scenarios" before(:each) do - expect_job_queued.with JobTypes::RefundCreatedJob, instance_of(Refund) end SCENARIOS.each do |example| @@ -16,119 +14,122 @@ context "for #{example[:source]}" do example[:refunds].each do |refund_ex| context "with following inputs #{refund_ex}" do - let(:transaction) { - Transaction.create( - supporter: original_payment.supporter, - transaction_assignments: [TransactionAssignment.new( - assignable: ModernDonation.new(amount: example[:amount], legacy_donation: original_donation))], - subtransaction: Subtransaction.new( - - subtransaction_payments: [ - SubtransactionPayment.new( - legacy_payment: charge.payment, - paymentable: StripeTransactionCharge.new + let(:transaction) { + Transaction.create( + supporter: original_payment.supporter, + transaction_assignments: [TransactionAssignment.new( + assignable: ModernDonation.new(amount: example[:amount], legacy_donation: original_donation) + )], + subtransaction: Subtransaction.new( + subtransaction_payments: [ + SubtransactionPayment.new( + legacy_payment: charge.payment, + paymentable: StripeTransactionCharge.new + ) + ], + subtransactable: StripeTransaction.new( + amount: example[:amount] ) - ], - subtransactable:StripeTransaction.new( - amount: example[:amount], ) - )) - } - - let(:original_donation) { - force_create(:donation, payment: original_payment, amount: example[:amount], - supporter: original_payment.supporter, - nonprofit: original_payment.nonprofit) - } - - let(:original_payment) { force_create(:payment, - gross_amount: example[:amount], - refund_total: beginning_refund_total, - net_amount: example[:amount], - fee_total: 0, - supporter: supporter, - nonprofit: nonprofit, - date: Time.current - ) - } - - let(:charge) { force_create(:charge, - amount: 10000, - stripe_charge_id: 'ch_test', - payment_id: original_payment.id, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id - )} - - let(:reason) { 'duplicate'} - let(:comment) {'comment'} - - let(:stripe_app_fee_refund) { Stripe::ApplicationFeeRefund.construct_from({amount: amount_of_fees_to_refund, id: 'app_fee_refund_1'})} - let(:stripe_refund) { Stripe::Refund.construct_from({id: 'refund_1'})} - let(:perform_stripe_refund_result) do - {stripe_refund: stripe_refund, stripe_app_fee_refund: amount_of_fees_to_refund > 0 ? stripe_app_fee_refund : nil} - end - - let(:refund) { Refund.last} - let(:refund_payment) { refund.payment} - let(:misc_refund_info) { refund.misc_refund_info} - - let(:amount_of_fees_to_refund) { refund_ex[:calculate_application_fee_refund_result]} - let(:amount_to_refund) { refund_ex[:amount_refunded]} - let(:beginning_refund_total) {refund_ex[:refunded_already]} - let(:ending_refund_total) { amount_to_refund + beginning_refund_total} - - before(:each) do - expect(InsertRefunds).to receive(:perform_stripe_refund).with( - nonprofit_id: nonprofit.id, refund_data:{ - 'amount' => amount_to_refund, - 'charge'=> charge.stripe_charge_id, - 'reason' => reason - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) - expect(InsertActivities).to receive(:for_refunds) - end - - let!(:modern_refund_call) do - transaction - InsertRefunds.modern_refund(charge.attributes.with_indifferent_access, { - amount: amount_to_refund, - comment: comment, - reason: reason - }.with_indifferent_access) - end - - it 'has an accurate refund_payment' do - expect(refund_payment.gross_amount).to eq -amount_to_refund - expect(refund_payment.fee_total).to eq amount_of_fees_to_refund - expect(refund_payment.net_amount).to eq -(amount_to_refund) + amount_of_fees_to_refund - expect(refund_payment.kind).to eq 'Refund' - end - - it 'has an accurate original_payment' do - original_payment.reload - - expect(original_payment.refund_total).to eq ending_refund_total - end - - it 'has an accurate refund' do - expect(refund.amount).to eq amount_to_refund - expect(refund.comment).to eq comment - expect(refund.reason).to eq reason - end - - it 'has an accurate misc_refund_info' do - expect(misc_refund_info.is_modern).to eq true - if amount_of_fees_to_refund > 0 - expect(misc_refund_info.stripe_application_fee_refund_id).to eq stripe_app_fee_refund.id - else - expect(misc_refund_info.stripe_application_fee_refund_id).to be_nil + ) + } + + let(:original_donation) { + force_create(:donation, payment: original_payment, amount: example[:amount], + supporter: original_payment.supporter, + nonprofit: original_payment.nonprofit) + } + + let(:original_payment) { + force_create(:payment, + gross_amount: example[:amount], + refund_total: beginning_refund_total, + net_amount: example[:amount], + fee_total: 0, + supporter: supporter, + nonprofit: nonprofit, + date: Time.current) + } + + let(:charge) { + force_create(:charge, + amount: 10000, + stripe_charge_id: "ch_test", + payment_id: original_payment.id, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id) + } + + let(:reason) { "duplicate" } + let(:comment) { "comment" } + + let(:stripe_app_fee_refund) { Stripe::ApplicationFeeRefund.construct_from({amount: amount_of_fees_to_refund, id: "app_fee_refund_1"}) } + let(:stripe_refund) { Stripe::Refund.construct_from({id: "refund_1"}) } + let(:perform_stripe_refund_result) do + {stripe_refund: stripe_refund, stripe_app_fee_refund: (amount_of_fees_to_refund > 0) ? stripe_app_fee_refund : nil} + end + + let(:refund) { Refund.last } + let(:refund_payment) { refund.payment } + let(:misc_refund_info) { refund.misc_refund_info } + + let(:amount_of_fees_to_refund) { refund_ex[:calculate_application_fee_refund_result] } + let(:amount_to_refund) { refund_ex[:amount_refunded] } + let(:beginning_refund_total) { refund_ex[:refunded_already] } + let(:ending_refund_total) { amount_to_refund + beginning_refund_total } + + before(:each) do + expect(InsertRefunds).to receive(:perform_stripe_refund).with( + nonprofit_id: nonprofit.id, refund_data: { + "amount" => amount_to_refund, + "charge" => charge.stripe_charge_id, + "reason" => reason + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) + expect(InsertActivities).to receive(:for_refunds) + end + + let!(:modern_refund_call) do + transaction + InsertRefunds.modern_refund(charge.attributes.with_indifferent_access, { + amount: amount_to_refund, + comment: comment, + reason: reason + }.with_indifferent_access) + end + + it "has an accurate refund_payment" do + expect(refund_payment.gross_amount).to eq(-amount_to_refund) + expect(refund_payment.fee_total).to eq amount_of_fees_to_refund + expect(refund_payment.net_amount).to eq(-amount_to_refund + amount_of_fees_to_refund) + expect(refund_payment.kind).to eq "Refund" + end + + it "has an accurate original_payment" do + original_payment.reload + + expect(original_payment.refund_total).to eq ending_refund_total + end + + it "has an accurate refund" do + expect(refund.amount).to eq amount_to_refund + expect(refund.comment).to eq comment + expect(refund.reason).to eq reason + end + + it "has an accurate misc_refund_info" do + expect(misc_refund_info.is_modern).to eq true + if amount_of_fees_to_refund > 0 + expect(misc_refund_info.stripe_application_fee_refund_id).to eq stripe_app_fee_refund.id + else + expect(misc_refund_info.stripe_application_fee_refund_id).to be_nil + end + end + end end end end end - end - end - end end end end diff --git a/spec/lib/insert/insert_source_token_spec.rb b/spec/lib/insert/insert_source_token_spec.rb index 8b2e690ae..3791d8aec 100644 --- a/spec/lib/insert/insert_source_token_spec.rb +++ b/spec/lib/insert/insert_source_token_spec.rb @@ -1,51 +1,54 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertSourceToken do - describe '.create_record' do - let(:event) {force_create(:event, end_datetime: Time.now + 1.day)} - describe 'param validation' do - it 'validates tokenizable' do - expect {InsertSourceToken.create_record(nil)}.to(raise_error {|error| + describe ".create_record" do + let(:event) { force_create(:event, end_datetime: Time.now + 1.day) } + describe "param validation" do + it "validates tokenizable" do + expect { InsertSourceToken.create_record(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :tokenizable, name: :required}]) }) end - it 'validates params' do - expect {InsertSourceToken.create_record(nil, event: '', expiration_time: 'j', max_uses: 'j')}.to(raise_error {|error| + it "validates params" do + expect { InsertSourceToken.create_record(nil, event: "", expiration_time: "j", max_uses: "j") }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {key: :tokenizable, name: :required}, - {key: :event, name: :is_a}, - {key: :expiration_time, name: :is_integer}, - {key: :expiration_time, name: :min}, - {key: :max_uses, name: :is_integer}, - {key: :max_uses, name: :min} + {key: :tokenizable, name: :required}, + {key: :event, name: :is_a}, + {key: :expiration_time, name: :is_integer}, + {key: :expiration_time, name: :min}, + {key: :max_uses, name: :is_integer}, + {key: :max_uses, name: :min} ]) }) end end - describe 'handles default' do - it 'without event' do + describe "handles default" do + it "without event" do Timecop.freeze(2020, 4, 5) do ouruuid = nil tokenizable = Card.create! - expect(SecureRandom).to receive(:uuid).and_wrap_original {|m| ouruuid = m.call(); ouruuid} + expect(SecureRandom).to receive(:uuid).and_wrap_original { |m| + ouruuid = m.call + ouruuid + } result = InsertSourceToken.create_record(tokenizable) expected = { - tokenizable_id: tokenizable.id, - tokenizable_type: 'Card', - token: ouruuid, - expiration: Time.now.since(20.minutes), - created_at: Time.now, - updated_at: Time.now, - total_uses: 0, - max_uses: 1, - event_id: nil + tokenizable_id: tokenizable.id, + tokenizable_type: "Card", + token: ouruuid, + expiration: Time.now.since(20.minutes), + created_at: Time.now, + updated_at: Time.now, + total_uses: 0, + max_uses: 1, + event_id: nil }.with_indifferent_access expect(result.attributes.with_indifferent_access).to eq expected @@ -54,25 +57,28 @@ end end - it 'with event' do + it "with event" do Timecop.freeze(2020, 4, 5) do ouruuid = nil tokenizable = Card.create! - expect(SecureRandom).to receive(:uuid).and_wrap_original {|m| ouruuid = m.call(); ouruuid} + expect(SecureRandom).to receive(:uuid).and_wrap_original { |m| + ouruuid = m.call + ouruuid + } result = InsertSourceToken.create_record(tokenizable, event: event) expected = { - tokenizable_id: tokenizable.id, - tokenizable_type: 'Card', - token: ouruuid, - expiration: Time.now + 1.day + 20.days, - created_at: Time.now, - updated_at: Time.now, - total_uses: 0, - max_uses: 20, - event_id: event.id + tokenizable_id: tokenizable.id, + tokenizable_type: "Card", + token: ouruuid, + expiration: Time.now + 1.day + 20.days, + created_at: Time.now, + updated_at: Time.now, + total_uses: 0, + max_uses: 20, + event_id: event.id }.with_indifferent_access expect(result.attributes).to eq expected @@ -81,62 +87,62 @@ end end end - describe 'handles passed in data' do - it 'without event' do - + describe "handles passed in data" do + it "without event" do Timecop.freeze(2020, 4, 5) do ouruuid = nil tokenizable = Card.create! - expect(SecureRandom).to receive(:uuid).and_wrap_original {|m| ouruuid = m.call(); ouruuid} + expect(SecureRandom).to receive(:uuid).and_wrap_original { |m| + ouruuid = m.call + ouruuid + } result = InsertSourceToken.create_record(tokenizable, max_uses: 50, expiration_time: 3600) expected = {tokenizable_id: tokenizable.id, - tokenizable_type: 'Card', + tokenizable_type: "Card", token: ouruuid, expiration: Time.now.since(1.hour), created_at: Time.now, updated_at: Time.now, total_uses: 0, max_uses: 50, - event_id: nil - }.with_indifferent_access + event_id: nil}.with_indifferent_access expect(result.attributes.with_indifferent_access).to eq expected expect(SourceToken.last.attributes).to eq expected end - end - it 'with event' do + it "with event" do Timecop.freeze(2020, 4, 5) do ouruuid = nil tokenizable = Card.create! - expect(SecureRandom).to receive(:uuid).and_wrap_original {|m| ouruuid = m.call(); ouruuid} + expect(SecureRandom).to receive(:uuid).and_wrap_original { |m| + ouruuid = m.call + ouruuid + } result = InsertSourceToken.create_record(tokenizable, max_uses: 50, expiration_time: 3600, event: event) expected = { - tokenizable_id: tokenizable.id, - tokenizable_type: 'Card', - token: ouruuid, - expiration: Time.now.since(1.day).since(1.hour), - created_at: Time.now, - updated_at: Time.now, - total_uses: 0, - max_uses: 50, - event_id: event.id + tokenizable_id: tokenizable.id, + tokenizable_type: "Card", + token: ouruuid, + expiration: Time.now.since(1.day).since(1.hour), + created_at: Time.now, + updated_at: Time.now, + total_uses: 0, + max_uses: 50, + event_id: event.id }.with_indifferent_access expect(result.attributes.with_indifferent_access).to eq expected expect(SourceToken.last.attributes).to eq expected + end + end end - -end - - - end end - end \ No newline at end of file +end diff --git a/spec/lib/insert/insert_supporter_spec.rb b/spec/lib/insert/insert_supporter_spec.rb index 2233c537e..d3a29980b 100644 --- a/spec/lib/insert/insert_supporter_spec.rb +++ b/spec/lib/insert/insert_supporter_spec.rb @@ -1,40 +1,40 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" describe InsertSupporter do - describe '.create_or_update' do + describe ".create_or_update" do let(:nonprofit) { create(:nonprofit) } let(:supporter_data) { { - 'email' => Faker::Internet.email, - 'name' => Faker::FunnyName.name, - 'phone' => Faker::PhoneNumber.cell_phone + "email" => Faker::Internet.email, + "name" => Faker::FunnyName.name, + "phone" => Faker::PhoneNumber.cell_phone } } let(:insert_supporter) { InsertSupporter.create_or_update(nonprofit.id, supporter_data) } - describe 'creates an object event' do - it 'of the right type' do - expect{ insert_supporter }.to change{ ObjectEvent.where(event_type: 'supporter.created').count }.by 1 + describe "creates an object event" do + it "of the right type" do + expect { insert_supporter }.to change { ObjectEvent.where(event_type: "supporter.created").count }.by 1 end - it 'with the correct information' do + it "with the correct information" do expect(insert_supporter.object_events.last.object_json).to include_json( id: insert_supporter.object_events.last.houid, data: { object: { id: insert_supporter.houid, - name: supporter_data['name'], - email: supporter_data['email'], - phone: supporter_data['phone'], - object: 'supporter', + name: supporter_data["name"], + email: supporter_data["email"], + phone: supporter_data["phone"], + object: "supporter", legacy_id: insert_supporter.id, legacy_nonprofit: nonprofit.id, nonprofit: nonprofit.houid } }, - type: 'supporter.created', - object: 'object_event', + type: "supporter.created", + object: "object_event", created: insert_supporter.object_events.last.created.to_i ) end diff --git a/spec/lib/insert/insert_tag_joins_spec.rb b/spec/lib/insert/insert_tag_joins_spec.rb index a6584743f..a3f38483a 100644 --- a/spec/lib/insert/insert_tag_joins_spec.rb +++ b/spec/lib/insert/insert_tag_joins_spec.rb @@ -1,59 +1,49 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" - -describe 'InsertTagJoins.in_bulk' do - - context 'parameter validation' do - it 'should validate parameters' do - - response = InsertTagJoins::in_bulk(nil, nil, 'no', nil) +describe "InsertTagJoins.in_bulk" do + context "parameter validation" do + it "should validate parameters" do + response = InsertTagJoins.in_bulk(nil, nil, "no", nil) errors = response[:json][:errors] expect(errors.length).to eq(6) - expect(response[:status]).to eq (:unprocessable_entity) + expect(response[:status]).to eq(:unprocessable_entity) expect_validation_errors(errors, [ - {key: :np_id, name: :required}, - {key: :np_id, name: :is_integer}, - {key: :profile_id, name: :required}, - {key: :profile_id, name: :is_integer}, - {key: :supporter_ids, name: :is_array}, - {key: :tag_data, name: :required} + {key: :np_id, name: :required}, + {key: :np_id, name: :is_integer}, + {key: :profile_id, name: :required}, + {key: :profile_id, name: :is_integer}, + {key: :supporter_ids, name: :is_array}, + {key: :tag_data, name: :required} ]) - end - context 'requiring db' do + context "requiring db" do before { @nonprofit = force_create(:nonprofit) @profile = force_create(:profile) } - it 'nonprofit must be valid' do - response = InsertTagJoins::in_bulk(@nonprofit.id+1, @profile.id, [1], []) - expect(response[:status]).to eq (:unprocessable_entity) - expect(response[:json][:error]).to include("Nonprofit #{@nonprofit.id+1} is not valid") + it "nonprofit must be valid" do + response = InsertTagJoins.in_bulk(@nonprofit.id + 1, @profile.id, [1], []) + expect(response[:status]).to eq(:unprocessable_entity) + expect(response[:json][:error]).to include("Nonprofit #{@nonprofit.id + 1} is not valid") end - it 'profile must be valid' do - response = InsertTagJoins::in_bulk(@nonprofit.id, @profile.id+1, [1], []) - expect(response[:status]).to eq (:unprocessable_entity) - expect(response[:json][:error]).to include("Profile #{@profile.id+1} is not valid") + it "profile must be valid" do + response = InsertTagJoins.in_bulk(@nonprofit.id, @profile.id + 1, [1], []) + expect(response[:status]).to eq(:unprocessable_entity) + expect(response[:json][:error]).to include("Profile #{@profile.id + 1} is not valid") end - it 'supporters if empty should do nothing' do - response = InsertTagJoins::in_bulk(@nonprofit.id, @profile.id, [], []) - expect(response).to eq(successful_json(0,0)) + it "supporters if empty should do nothing" do + response = InsertTagJoins.in_bulk(@nonprofit.id, @profile.id, [], []) + expect(response).to eq(successful_json(0, 0)) end - - end - - - end - context 'supporters tags' do + context "supporters tags" do before(:each) { - @nonprofit = force_create(:nonprofit) @profile = force_create(:profile) @@ -64,87 +54,83 @@ @add_tags = [25, 35] @supporters = { - :np_supporter_with_add => { - :creation_hash => {:nonprofit => @nonprofit }, - :tag_ids => [65, 75 ,85] - }, - :np_supporter_with_tags_to_delete => { - :creation_hash => {:nonprofit => @nonprofit }, - :tag_ids => [40, 75, 85] - }, - - :np_supporter_with_no_changes => { - :creation_hash => {:nonprofit => @nonprofit}, - :tag_ids => @add_tags - }, - :np_supporter_with_some_of_both => { - :creation_hash => {:nonprofit => @nonprofit}, - :tag_ids => [20, 35] - }, - :supporter_from_other_np => { - :creation_hash => {:nonprofit => @other_nonprofit}, - :tag_ids => [100, 150, 200] - } + np_supporter_with_add: { + creation_hash: {nonprofit: @nonprofit}, + tag_ids: [65, 75, 85] + }, + np_supporter_with_tags_to_delete: { + creation_hash: {nonprofit: @nonprofit}, + tag_ids: [40, 75, 85] + }, + + np_supporter_with_no_changes: { + creation_hash: {nonprofit: @nonprofit}, + tag_ids: @add_tags + }, + np_supporter_with_some_of_both: { + creation_hash: {nonprofit: @nonprofit}, + tag_ids: [20, 35] + }, + supporter_from_other_np: { + creation_hash: {nonprofit: @other_nonprofit}, + tag_ids: [100, 150, 200] + } } @supporters = { - :np_supporter_with_add => { - :tag_ids => [65, 75 ,85] - }, - :np_supporter_with_tags_to_delete => { - :tag_ids => [40, 75, 85] - }, - - :np_supporter_with_no_changes => { - :tag_ids => @add_tags - }, - :np_supporter_with_some_of_both => { - - :tag_ids => [20, 35] - }, - :supporter_from_other_np => { - :tag_ids => [100, 150, 200], - :other_np => true - } + np_supporter_with_add: { + tag_ids: [65, 75, 85] + }, + np_supporter_with_tags_to_delete: { + tag_ids: [40, 75, 85] + }, + + np_supporter_with_no_changes: { + tag_ids: @add_tags + }, + np_supporter_with_some_of_both: { + + tag_ids: [20, 35] + }, + supporter_from_other_np: { + tag_ids: [100, 150, 200], + other_np: true + } } @supporters.each_key { |k| i = @supporters[k] - nonprofit_for_supporter =i[:other_np] ? @other_nonprofit: @nonprofit - i[:entity] = create(:supporter, :nonprofit => nonprofit_for_supporter) - i[:tag_ids].each { |j | - - tm = TagMaster.exists?(id: j) ? TagMaster.find(j): create(:tag_master, id: j, nonprofit: nonprofit_for_supporter, name: "TM #{j}") - - create(:tag_join, :supporter_id => i[:entity].id, :tag_master => tm)} + nonprofit_for_supporter = i[:other_np] ? @other_nonprofit : @nonprofit + i[:entity] = create(:supporter, nonprofit: nonprofit_for_supporter) + i[:tag_ids].each { |j| + tm = TagMaster.exists?(id: j) ? TagMaster.find(j) : create(:tag_master, id: j, nonprofit: nonprofit_for_supporter, name: "TM #{j}") + create(:tag_join, supporter_id: i[:entity].id, tag_master: tm) + } } - } - it 'invalid nonprofit-supporter combo returns okay' do - results = InsertTagJoins::in_bulk(@nonprofit.id,@profile.id, [@supporters[:supporter_from_other_np][:entity].id], {}) + it "invalid nonprofit-supporter combo returns okay" do + results = InsertTagJoins.in_bulk(@nonprofit.id, @profile.id, [@supporters[:supporter_from_other_np][:entity].id], {}) expect(results).to eq(successful_json(0, 0)) end - it 'strips tags which dont belong to nonprofit' do - results = InsertTagJoins::in_bulk(@nonprofit.id,@profile.id, [@supporters[:np_supporter_with_add][:entity].id], - create_tag_data([100], [150])) + it "strips tags which dont belong to nonprofit" do + results = InsertTagJoins.in_bulk(@nonprofit.id, @profile.id, [@supporters[:np_supporter_with_add][:entity].id], + create_tag_data([100], [150])) expect(results).to eq(successful_json(0, 0)) - expect(TagJoin.where('supporter_id = ? and tag_master_id = ?', @supporters[:np_supporter_with_add][:entity].id, 100).count).to eq 0 - + expect(TagJoin.where("supporter_id = ? and tag_master_id = ?", @supporters[:np_supporter_with_add][:entity].id, 100).count).to eq 0 end - it 'delete' do - + it "delete" do expect(TagJoin.count).to eq 13 @supporters[:np_supporter_with_some_of_both][:entity].id - results = InsertTagJoins::in_bulk(@nonprofit.id, @profile.id, - [@supporters[:np_supporter_with_some_of_both][:entity].id, @supporters[:np_supporter_with_tags_to_delete][:entity].id, @supporters[:np_supporter_with_add][:entity].id, @supporters[:supporter_from_other_np][:entity].id, @supporters[:np_supporter_with_no_changes][:entity].id], - create_tag_data(@add_tags, @delete_tags)) + InsertTagJoins.in_bulk(@nonprofit.id, @profile.id, + [@supporters[:np_supporter_with_some_of_both][:entity].id, @supporters[:np_supporter_with_tags_to_delete][:entity].id, @supporters[:np_supporter_with_add][:entity].id, @supporters[:supporter_from_other_np][:entity].id, @supporters[:np_supporter_with_no_changes][:entity].id], + create_tag_data(@add_tags, @delete_tags)) expect(TagJoin.where("supporter_id = ? ", @supporters[:np_supporter_with_some_of_both][:entity].id).count).to eq 2 @@ -157,14 +143,9 @@ expect(TagJoin.where("supporter_id = ?", @supporters[:np_supporter_with_no_changes][:entity].id).count).to eq 2 expect(TagJoin.count).to eq 16 - - - - end - it 'add_to_one' do - + it "add_to_one" do expect(TagJoin.count).to eq 13 np_supporter_with_add_tags = @supporters[:np_supporter_with_add][:entity].tag_joins.to_a @@ -172,55 +153,47 @@ np_supporter_with_no_changes_tags = @supporters[:np_supporter_with_no_changes][:entity].tag_joins.to_a Timecop.travel(20) { - - - results = InsertTagJoins::in_bulk(@nonprofit.id, @profile.id, - [ - @supporters[:np_supporter_with_add][:entity].id, #add 2 - @supporters[:np_supporter_with_no_changes][:entity], # update 2 - @supporters[:np_supporter_with_some_of_both][:entity].id], #add 2, delete 1 - create_tag_data(@add_tags, @delete_tags)) + results = InsertTagJoins.in_bulk(@nonprofit.id, @profile.id, + [ + @supporters[:np_supporter_with_add][:entity].id, # add 2 + @supporters[:np_supporter_with_no_changes][:entity], # update 2 + @supporters[:np_supporter_with_some_of_both][:entity].id + ], # add 2, delete 1 + create_tag_data(@add_tags, @delete_tags)) expect(results).to eq(successful_json(6, 1)) - - expect(@supporters[:np_supporter_with_no_changes][:entity].tag_joins).to match_array(np_supporter_with_no_changes_tags) expect(TagJoin.where("supporter_id = ? ", @supporters[:np_supporter_with_add][:entity].id).count).to eq 5 original_db_pairs = get_original_and_db(np_supporter_with_add_tags, TagJoin.where("supporter_id = ? and tag_master_id in (?)", - @supporters[:np_supporter_with_add][:entity].id, - @supporters[:np_supporter_with_add][:tag_ids]).pluck(:id)) + @supporters[:np_supporter_with_add][:entity].id, + @supporters[:np_supporter_with_add][:tag_ids]).pluck(:id)) - original_db_pairs.each {|orig, db| + original_db_pairs.each { |orig, db| expect(orig.attributes.length).to eq(db.attributes.length) expect(orig.attributes).to eq(db.attributes) } expect(TagJoin.where("supporter_id = ?", @supporters[:np_supporter_with_some_of_both][:entity].id).count).to eq 2 - original_db_pairs = get_original_and_db(np_supporter_with_some_of_both_tags, TagJoin.where("supporter_id = ? and tag_master_id in (?)", - @supporters[:np_supporter_with_some_of_both][:entity].id, - [35]).pluck(:id)) - original_db_pairs.each {|orig, db| + @supporters[:np_supporter_with_some_of_both][:entity].id, + [35]).pluck(:id)) + original_db_pairs.each { |orig, db| expect(orig.attributes.length).to eq(db.attributes.length) - expect(orig.attributes.select{|key, value| key != 'updated_at'}).to eq(db.attributes.select{|key, value| key != 'updated_at'}) - expect(orig.attributes['updated_at']).to be < db.attributes['updated_at'] + expect(orig.attributes.select { |key, value| key != "updated_at" }).to eq(db.attributes.select { |key, value| key != "updated_at" }) + expect(orig.attributes["updated_at"]).to be < db.attributes["updated_at"] } expect(TagJoin.count).to eq 15 - } - - end end - def get_original_and_db(original_items, ids_to_verify) - ids_to_verify.map {|i| + ids_to_verify.map { |i| original_item = original_items.find { |oi| oi[:id] == i } db_item = TagJoin.find(i) [original_item, db_item] @@ -228,14 +201,10 @@ def get_original_and_db(original_items, ids_to_verify) end def successful_json(inserted, deleted) - {:json => {:inserted_count => inserted, :removed_count => deleted}, :status => :ok} + {json: {inserted_count: inserted, removed_count: deleted}, status: :ok} end - - def create_tag_data(tags_to_add =[], tags_to_delete=[]) - tags_to_add.map{|tag| {tag_master_id: tag, selected: true}} + tags_to_delete.map{|tag| {tag_master_id: tag, selected: false}} + def create_tag_data(tags_to_add = [], tags_to_delete = []) + tags_to_add.map { |tag| {tag_master_id: tag, selected: true} } + tags_to_delete.map { |tag| {tag_master_id: tag, selected: false} } end end - - - diff --git a/spec/lib/insert/insert_tickets_spec.rb b/spec/lib/insert/insert_tickets_spec.rb index a83690ad6..8d7f55d86 100644 --- a/spec/lib/insert/insert_tickets_spec.rb +++ b/spec/lib/insert/insert_tickets_spec.rb @@ -1,199 +1,198 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InsertTickets do include_context :shared_rd_donation_value_context - let(:switchover_date) { Time.new(2020,10,1)} - before(:each) do - stub_const('FEE_SWITCHOVER_TIME', switchover_date) + let(:switchover_date) { Time.new(2020, 10, 1) } + before(:each) do + stub_const("FEE_SWITCHOVER_TIME", switchover_date) end # @param [Object] data def generate_expected_tickets(data = {}) - amount = data[:gross_amount] || 2000 data[:payment_fee_total] = data[:payment_fee_total] || 0 - result = { - payment: { - date: Time.now, - donation_id: nil, - fee_total: -1 * data[:payment_fee_total], - gross_amount: amount, - id: data[:payment_id] || 55555, - kind: data[:kind] || 'Ticket', - net_amount: amount - data[:payment_fee_total] , - nonprofit_id: data[:nonprofit].id, - refund_total: 0, - supporter_id: data[:supporter].id, - towards: data[:event].name, - created_at: Time.now, - updated_at: Time.now - } - }.with_indifferent_access + result = { + payment: { + date: Time.now, + donation_id: nil, + fee_total: -1 * data[:payment_fee_total], + gross_amount: amount, + id: data[:payment_id] || 55555, + kind: data[:kind] || "Ticket", + net_amount: amount - data[:payment_fee_total], + nonprofit_id: data[:nonprofit].id, + refund_total: 0, + supporter_id: data[:supporter].id, + towards: data[:event].name, + created_at: Time.now, + updated_at: Time.now + } + }.with_indifferent_access - if data[:offsite_payment] - result[:offsite_payment] = { - id: data[:offsite_payment][:id], - nonprofit_id: nonprofit.id, + if data[:offsite_payment] + result[:offsite_payment] = { + id: data[:offsite_payment][:id], + nonprofit_id: nonprofit.id, supporter_id: supporter.id, date: Time.current, payment_id: data[:payment_id], kind: data[:offsite_payment][:kind], - check_number: data[:offsite_payment][:check_number], + check_number: data[:offsite_payment][:check_number], created_at: Time.now, - updated_at: Time.now, - gross_amount: amount, + updated_at: Time.now, + gross_amount: amount, - donation_id: nil, - user_id: nil - } - end - unless (data[:charge_id] == nil) - result[:activity] = {} - - result[:charge] = { - id: data[:charge_id] || 55555, - amount: amount, - card_id: data[:card].id, - created_at: Time.now, - updated_at: Time.now, - stripe_charge_id: data[:stripe_charge_id], - fee: data[:payment_fee_total], - disbursed: nil, - failure_message: nil, - payment_id: data[:payment_id] || 55555, - nonprofit_id: data[:nonprofit].id, - status: 'pending', - profile_id: nil, - supporter_id: data[:supporter].id, - - donation_id: nil, - - direct_debit_detail_id: nil, - - - #deletable - ticket_id: nil - } - end + donation_id: nil, + user_id: nil + } + end + unless data[:charge_id].nil? + result[:activity] = {} - result[:tickets] = data[:tickets].map.with_index{|item, i| - { - id: item[:id], - quantity: item[:quantity], - ticket_level_id: item[:ticket_level_id], - ticket_purchase_id: item[:ticket_purchase_id], - event_id: data[:event].id, - supporter_id: data[:supporter].id, - payment_id: data[:payment_id], - charge_id: data[:charge_id] || nil, - event_discount_id: data[:event_discount_id], - created_at: Time.now, - updated_at: Time.now, + result[:charge] = { + id: data[:charge_id] || 55555, + amount: amount, + card_id: data[:card].id, + created_at: Time.now, + updated_at: Time.now, + stripe_charge_id: data[:stripe_charge_id], + fee: data[:payment_fee_total], + disbursed: nil, + failure_message: nil, + payment_id: data[:payment_id] || 55555, + nonprofit_id: data[:nonprofit].id, + status: "pending", + profile_id: nil, + supporter_id: data[:supporter].id, + + donation_id: nil, + + direct_debit_detail_id: nil, + + # deletable + ticket_id: nil + } + end + + result[:tickets] = data[:tickets].map.with_index { |item, i| + { + id: item[:id], + quantity: item[:quantity], + ticket_level_id: item[:ticket_level_id], + ticket_purchase_id: item[:ticket_purchase_id], + event_id: data[:event].id, + supporter_id: data[:supporter].id, + payment_id: data[:payment_id], + charge_id: data[:charge_id] || nil, + event_discount_id: data[:event_discount_id], + created_at: Time.now, + updated_at: Time.now, checked_in: nil, - bid_id: i+1, + bid_id: i + 1, card_id: nil, - profile_id: nil, - note: nil, - deleted: false, - source_token_id: nil - }.with_indifferent_access - } + profile_id: nil, + note: nil, + deleted: false, + source_token_id: nil + }.with_indifferent_access + } result.with_indifferent_access - - - end def success_expectations - - expect(InsertTickets).to receive(:generated_ticket_entities).and_wrap_original{|m, *args| - tickets = m.call(*args); - ticket_ids = tickets.map{|t| t.id} + expect(InsertTickets).to receive(:generated_ticket_entities).and_wrap_original { |m, *args| + tickets = m.call(*args) + ticket_ids = tickets.map { |t| t.id } expect(InsertActivities).to receive(:for_tickets).with(ticket_ids) expect_job_queued.with(JobTypes::TicketMailerReceiptAdminJob, ticket_ids).once # TODO the `anything` should be the charge_id but don't have an obvious way of getting that now. expect_job_queued.with(JobTypes::TicketMailerFollowupJob, ticket_ids, anything).once tickets } - end - describe '.create' do - it 'does basic validation' do - expect {InsertTickets.create(event_discount_id: 'etheht', - kind: 'blah', - token: 'none')}.to raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [ - {key: :tickets, name: :required}, - {key: :tickets, name: :is_array}, - {key: :nonprofit_id, name: :required}, - {key: :nonprofit_id, name: :is_reference}, - {key: :supporter_id, name: :required}, - {key: :supporter_id, name: :is_reference}, - {key: :event_discount_id, name: :is_reference}, - {key: :kind, name: :included_in}, - {key: :token, name: :format}, - {key: :event_id, name: :is_reference}, - {key: :event_id, name: :required}, - {key: :amount, name: :is_integer}, - {key: :amount, name: :required}, - ]) - }.and not_change {ObjectEvent.count} + describe ".create" do + it "does basic validation" do + expect { + InsertTickets.create(event_discount_id: "etheht", + kind: "blah", + token: "none") + }.to raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, [ + {key: :tickets, name: :required}, + {key: :tickets, name: :is_array}, + {key: :nonprofit_id, name: :required}, + {key: :nonprofit_id, name: :is_reference}, + {key: :supporter_id, name: :required}, + {key: :supporter_id, name: :is_reference}, + {key: :event_discount_id, name: :is_reference}, + {key: :kind, name: :included_in}, + {key: :token, name: :format}, + {key: :event_id, name: :is_reference}, + {key: :event_id, name: :required}, + {key: :amount, name: :is_integer}, + {key: :amount, name: :required} + ]) + }.and not_change { ObjectEvent.count } # test that the quantity ticket_level validation works (it really doesn't very well) - expect {InsertTickets.create(event_discount_id: 'etheht', - kind: 'blah', - token: 'none', tickets: 2, offsite_payment: 'bhb', amount: 1400)}.to raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [ - {key: :tickets, name: :is_array}, - {key: :nonprofit_id, name: :required}, - {key: :nonprofit_id, name: :is_reference}, - {key: :supporter_id, name: :required}, - {key: :supporter_id, name: :is_reference}, - {key: :event_id, name: :is_reference}, - {key: :event_id, name: :required}, - {key: :event_discount_id, name: :is_reference}, - {key: :kind, name: :included_in}, - {key: :token, name: :format}, - {key: :offsite_payment, name: :is_hash} - ]) - }.and not_change {ObjectEvent.count} - - + expect { + InsertTickets.create(event_discount_id: "etheht", + kind: "blah", + token: "none", tickets: 2, offsite_payment: "bhb", amount: 1400) + }.to raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, [ + {key: :tickets, name: :is_array}, + {key: :nonprofit_id, name: :required}, + {key: :nonprofit_id, name: :is_reference}, + {key: :supporter_id, name: :required}, + {key: :supporter_id, name: :is_reference}, + {key: :event_id, name: :is_reference}, + {key: :event_id, name: :required}, + {key: :event_discount_id, name: :is_reference}, + {key: :kind, name: :included_in}, + {key: :token, name: :format}, + {key: :offsite_payment, name: :is_hash} + ]) + }.and not_change { ObjectEvent.count } end - it 'validates the ticket hashes' do - expect {InsertTickets.create(nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - event_id: event.id, - tickets: [{quantity: 1, ticket_level_id: 1}, {}], amount: 1400)}.to raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [ - {key: :quantity, name: :is_integer}, - {key: :quantity, name: :min}, - {key: :quantity, name: :required}, - {key: :ticket_level_id, name: :is_reference}, - {key: :ticket_level_id, name: :required} - ]) - }.and not_change {ObjectEvent.count} + it "validates the ticket hashes" do + expect { + InsertTickets.create(nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + event_id: event.id, + tickets: [{quantity: 1, ticket_level_id: 1}, {}], amount: 1400) + }.to raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, [ + {key: :quantity, name: :is_integer}, + {key: :quantity, name: :min}, + {key: :quantity, name: :required}, + {key: :ticket_level_id, name: :is_reference}, + {key: :ticket_level_id, name: :required} + ]) + }.and not_change { ObjectEvent.count } end - it 'validates the offsite_payment hash' do - expect {InsertTickets.create(nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - event_id: event.id, - tickets: [{quantity: 1, ticket_level_id: 1}], - offsite_payment: {kind: 'not in list'}, amount: 1400)}.to raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [ - {key: :kind, name: :included_in} - ]) - }.and not_change {ObjectEvent.count} + it "validates the offsite_payment hash" do + expect { + InsertTickets.create(nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + event_id: event.id, + tickets: [{quantity: 1, ticket_level_id: 1}], + offsite_payment: {kind: "not in list"}, amount: 1400) + }.to raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError + expect_validation_errors(error.data, [ + {key: :kind, name: :included_in} + ]) + }.and not_change { ObjectEvent.count } end # it 'errors out if token is invalid' do @@ -212,154 +211,146 @@ def success_expectations # validation_card_not_with_supporter {InsertTickets.create(tickets:[{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: other_source_token.token, event_id: event.id)} # end - - describe 'errors during find if' do - it 'supporter is invalid' do - find_error_supporter {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: 55555, token: source_token.token, event_id: event.id, amount: 1400)} + describe "errors during find if" do + it "supporter is invalid" do + find_error_supporter { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: 55555, token: source_token.token, event_id: event.id, amount: 1400) } end - it 'nonprofit is invalid' do - find_error_nonprofit {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: 55555, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400)} + it "nonprofit is invalid" do + find_error_nonprofit { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: 55555, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400) } end - - it 'event is invalid' do - find_error_event {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: 5555)} + it "event is invalid" do + find_error_event { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], amount: charge_amount, nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: 5555) } end end - describe 'errors during relationship comparison if' do - it 'supporter is deleted' do - validation_supporter_deleted {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400)} + describe "errors during relationship comparison if" do + it "supporter is deleted" do + validation_supporter_deleted { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400) } end - it 'ticket level is deleted' do - + it "ticket level is deleted" do ticket_level.deleted = true ticket_level.save! - expect {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400)}.to raise_error {|error| - + expect { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :tickets}]) - expect(error.message).to include 'deleted' + expect(error.message).to include "deleted" expect(error.message).to include "Ticket level #{ticket_level.id}" - }.and not_change {ObjectEvent.count} + }.and not_change { ObjectEvent.count } end - it 'event is deleted' do - validation_event_deleted {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400)} + it "event is deleted" do + validation_event_deleted { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400) } end - it 'supporter doesnt belong to nonprofit' do - validation_supporter_not_with_nonprofit {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: other_nonprofit_supporter.id, token: source_token.token, event_id: event.id, amount: 1400)} + it "supporter doesnt belong to nonprofit" do + validation_supporter_not_with_nonprofit { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: other_nonprofit_supporter.id, token: source_token.token, event_id: event.id, amount: 1400) } end - it 'event doesnt belong to nonprofit' do - validation_event_not_with_nonprofit {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: other_ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: other_event.id, amount: 1400)} + it "event doesnt belong to nonprofit" do + validation_event_not_with_nonprofit { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: other_ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: other_event.id, amount: 1400) } end - it 'event discount doesnt belong to event' do - expect {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, event_discount_id: other_event_discount.id, amount: 1400)}.to raise_error {|e| - + it "event discount doesnt belong to event" do + expect { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, event_discount_id: other_event_discount.id, amount: 1400) }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :event_discount_id}]) expect(e.message).to include "Event discount #{other_event_discount.id}" expect(e.message).to include "event #{event.id}" - }.and not_change {ObjectEvent.count} + }.and not_change { ObjectEvent.count } end end - it 'verify ticket not available raises properly' do + it "verify ticket not available raises properly" do expected_error = NotEnoughQuantityError.new(TicketLevel, nil, nil, nil) expect(QueryTicketLevels).to receive(:verify_tickets_available).and_raise(expected_error) - expect {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400)}.to raise_error(expected_error).and not_change {ObjectEvent.count} + expect { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 1400) }.to raise_error(expected_error).and not_change { ObjectEvent.count } end - describe 'gross_amount > 0' do + describe "gross_amount > 0" do around(:each) do |example| - Timecop.freeze(2020, 5, 4) do - example.run - end + Timecop.freeze(2020, 5, 4) do + example.run + end end - + before(:each) { - #for simplicity, we mock this to $20.00 no matter the ticket choices + # for simplicity, we mock this to $20.00 no matter the ticket choices expect(QueryTicketLevels).to receive(:gross_amount_from_tickets).at_least(:once).at_most(:twice).and_return(1600) } - describe 'and kind == offsite' do - - describe 'errors without current_user' do - let(:result) {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, 'kind' => 'offsite', amount:1600)} - it 'to raise error' do - expect { result }.to raise_error {|e| + describe "and kind == offsite" do + describe "errors without current_user" do + let(:result) { InsertTickets.create(:tickets => [{quantity: 1, ticket_level_id: ticket_level.id}], :nonprofit_id => nonprofit.id, :supporter_id => supporter.id, :token => source_token.token, :event_id => event.id, "kind" => "offsite", :amount => 1600) } + it "to raise error" do + expect { result }.to raise_error { |e| expect(e).to be_a AuthenticationError - }.and not_change {ObjectEvent.count} + }.and not_change { ObjectEvent.count } end end - describe 'errors with unauthorized current_user' do - let(:result) { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, kind: 'offsite', current_user: user, amount:1600) } - it 'raises error' do + describe "errors with unauthorized current_user" do + let(:result) { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, kind: "offsite", current_user: user, amount: 1600) } + it "raises error" do expect(QueryRoles).to receive(:is_authorized_for_nonprofit?).with(user.id, nonprofit.id).and_return(false) - expect { result }.to raise_error {|e| + expect { result }.to raise_error { |e| expect(e).to be_a AuthenticationError - }.and not_change {ObjectEvent.count} + }.and not_change { ObjectEvent.count } end end - describe 'succeeds' do - - let(:result ) { + describe "succeeds" do + let(:result) { expect(QueryRoles).to receive(:is_authorized_for_nonprofit?).with(user.id, nonprofit.id).and_return true - InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, kind: 'offsite', offsite_payment: {kind: 'check', check_number: 'fake_checknumber'}, current_user: user, amount: 1600) + InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, kind: "offsite", offsite_payment: {kind: "check", check_number: "fake_checknumber"}, current_user: user, amount: 1600) } - it 'has normal results' do + it "has normal results" do success_expectations - ticket_purchase = result['tickets'][0].ticket_purchase - expected = generate_expected_tickets(payment_id: result['payment'].id, - nonprofit: nonprofit, - supporter: supporter, - event: event, - gross_amount: 1600, - kind: 'OffsitePayment', - offsite_payment: {id: result['offsite_payment'].id, kind: 'check', check_number:'fake_checknumber'}, - tickets: [{ - id: result['tickets'][0]['id'], - quantity: 1, - ticket_level_id: ticket_level.id, - ticket_purchase_id: ticket_purchase.id - }]) - expect(result['payment'].attributes).to eq expected[:payment] - expect(result['offsite_payment'].attributes).to eq expected[:offsite_payment] - expect(result['tickets'].map{|i| i.attributes}[0]).to eq expected[:tickets][0] - - expect(result['tickets'].map(&:ticket_purchase)).to contain_exactly TicketPurchase.last + ticket_purchase = result["tickets"][0].ticket_purchase + expected = generate_expected_tickets(payment_id: result["payment"].id, + nonprofit: nonprofit, + supporter: supporter, + event: event, + gross_amount: 1600, + kind: "OffsitePayment", + offsite_payment: {id: result["offsite_payment"].id, kind: "check", check_number: "fake_checknumber"}, + tickets: [{ + id: result["tickets"][0]["id"], + quantity: 1, + ticket_level_id: ticket_level.id, + ticket_purchase_id: ticket_purchase.id + }]) + expect(result["payment"].attributes).to eq expected[:payment] + expect(result["offsite_payment"].attributes).to eq expected[:offsite_payment] + expect(result["tickets"].map { |i| i.attributes }[0]).to eq expected[:tickets][0] + + expect(result["tickets"].map(&:ticket_purchase)).to contain_exactly TicketPurchase.last end - - it 'increases object events by 2' do - expect { result }.to change {ObjectEvent.count}.by(2) + it "increases object events by 2" do + expect { result }.to change { ObjectEvent.count }.by(2) end - it 'increases offline_transaction_charge.created by 1' do - expect { result }.to change {ObjectEvent.where(event_type: 'offline_transaction_charge.created').count}.by(1) + it "increases offline_transaction_charge.created by 1" do + expect { result }.to change { ObjectEvent.where(event_type: "offline_transaction_charge.created").count }.by(1) end - it 'increases transaction.created by 1' do - expect { result }.to change {ObjectEvent.where(event_type: 'transaction.created').count}.by(1) + it "increases transaction.created by 1" do + expect { result }.to change { ObjectEvent.where(event_type: "transaction.created").count }.by(1) end - it 'increases Transaction by 1' do - expect { result }.to change {Transaction.count}.by(1) + it "increases Transaction by 1" do + expect { result }.to change { Transaction.count }.by(1) end - it 'increases TicketPurchase by 1' do - expect { result }.to change {TicketPurchase.count}.by(1) + it "increases TicketPurchase by 1" do + expect { result }.to change { TicketPurchase.count }.by(1) end - it 'creates a subtransaction payment whose creation date matches the legacy payment\'s date' do - legacy_payment = result['payment'] + it "creates a subtransaction payment whose creation date matches the legacy payment's date" do + legacy_payment = result["payment"] subtransaction_payment = legacy_payment.subtransaction_payment expect(subtransaction_payment.created).to eq(legacy_payment.date) @@ -367,9 +358,7 @@ def success_expectations end end - describe 'and kind == charge || nil' do - - + describe "and kind == charge || nil" do let(:basic_valid_ticket_input) { {tickets: [{quantity: 1, ticket_level_id: ticket_level.id}, {quantity: 2, ticket_level_id: ticket_level2.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, event_id: event.id, amount: 1600} } @@ -378,93 +367,76 @@ def success_expectations } let(:include_valid_token) { - basic_valid_ticket_input.merge({token: source_token.token}) + basic_valid_ticket_input.merge({token: source_token.token}) } - describe 'kind == charge' do - it 'token is invalid' do - - validation_invalid_token {InsertTickets.create(include_fake_token.merge({kind: 'charge'}))} - + describe "kind == charge" do + it "token is invalid" do + validation_invalid_token { InsertTickets.create(include_fake_token.merge({kind: "charge"})) } end - it 'errors out if token is unauthorized' do - - validation_unauthorized {InsertTickets.create(include_fake_token.merge({kind: 'charge'}))} - + it "errors out if token is unauthorized" do + validation_unauthorized { InsertTickets.create(include_fake_token.merge({kind: "charge"})) } end - it 'errors out if token is expired' do - - validation_expired {InsertTickets.create(include_fake_token.merge({kind: 'charge'}))} - + it "errors out if token is expired" do + validation_expired { InsertTickets.create(include_fake_token.merge({kind: "charge"})) } end - it 'card doesnt belong to supporter' do - - validation_card_not_with_supporter {InsertTickets.create(include_fake_token.merge({kind: 'charge', token: other_source_token.token}))} - + it "card doesnt belong to supporter" do + validation_card_not_with_supporter { InsertTickets.create(include_fake_token.merge({kind: "charge", token: other_source_token.token})) } end - it 'nonprofit isnt vetted' do + it "nonprofit isnt vetted" do find_error_nonprofit do nonprofit.update(vetted: false) - InsertTickets.create(include_fake_token.merge({kind: 'charge', token: other_source_token.token})) + InsertTickets.create(include_fake_token.merge({kind: "charge", token: other_source_token.token})) end end end - describe 'kind == nil' do - it 'token is invalid' do - - validation_invalid_token {InsertTickets.create(include_fake_token)} - + describe "kind == nil" do + it "token is invalid" do + validation_invalid_token { InsertTickets.create(include_fake_token) } end - it 'errors out if token is unauthorized' do - - validation_unauthorized {InsertTickets.create(include_fake_token)} - + it "errors out if token is unauthorized" do + validation_unauthorized { InsertTickets.create(include_fake_token) } end - it 'errors out if token is expired' do - - validation_expired {InsertTickets.create(include_fake_token)} - + it "errors out if token is expired" do + validation_expired { InsertTickets.create(include_fake_token) } end - it 'card doesnt belong to supporter' do - - validation_card_not_with_supporter {InsertTickets.create(include_fake_token.merge({kind: 'charge', token: other_source_token.token}))} - + it "card doesnt belong to supporter" do + validation_card_not_with_supporter { InsertTickets.create(include_fake_token.merge({kind: "charge", token: other_source_token.token})) } end end - it 'handles charge failed' do - handle_charge_failed {InsertTickets.create(include_valid_token)} + it "handles charge failed" do + handle_charge_failed { InsertTickets.create(include_valid_token) } end - - it 'succeeds' do - result = success({amount: 1600, fee:118}) - p = Payment.find(result['payment']['id']) + it "succeeds" do + result = success({amount: 1600, fee: 118}) + p = Payment.find(result["payment"]["id"]) expect(p.misc_payment_info&.fee_covered).to be_nil end - it 'succeeds if offsite_donation is there with empty kind' do + it "succeeds if offsite_donation is there with empty kind" do result = success({offsite_donation: {kind: nil}, amount: 1600, fee: 118}) - p = Payment.find(result['payment']['id']) + p = Payment.find(result["payment"]["id"]) expect(p.misc_payment_info&.fee_covered).to be_nil end - it 'succeeds if fee is covered' do - result = success({fee_covered:true, amount: 1680, fee:123}) - p = Payment.find(result['payment']['id']) + it "succeeds if fee is covered" do + result = success({fee_covered: true, amount: 1680, fee: 123}) + p = Payment.find(result["payment"]["id"]) expect(p.misc_payment_info&.fee_covered).to eq true end - def success(other_elements={}) - nonprofit.stripe_account_id = Stripe::Account.create()['id'] + def success(other_elements = {}) + nonprofit.stripe_account_id = Stripe::Account.create["id"] nonprofit.save! c = Stripe::Customer.create source = Stripe::Customer.create_source(c.id, {source: StripeMockHelper.generate_card_token}) @@ -473,7 +445,7 @@ def success(other_elements={}) card.save! success_expectations - + insert_charge_expectation = { kind: "Ticket", towards: event.name, @@ -493,74 +465,75 @@ def success(other_elements={}) expect(Stripe::Charge).to receive(:create).with({application_fee_amount: other_elements[:fee], customer: c.id, amount: other_elements[:amount], - currency: 'usd', - description: 'Tickets The event of Wonders', - statement_descriptor_suffix: 'Tickets The event of W', - metadata: {kind: 'Ticket', event_id: event.id, nonprofit_id: nonprofit.id}, - transfer_data:{destination: "test_acct_1"}, - on_behalf_of:"test_acct_1" - }, {stripe_version: "2019-09-09"}).and_wrap_original{|m, *args| a= m.call(*args); - stripe_charge_id = a['id'] - a} - result = InsertTickets.create(include_valid_token.merge(event_discount_id:event_discount.id).merge(fee_covered: other_elements[:fee_covered], amount: other_elements[:amount])) - tp = result['tickets'][0].ticket_purchase + currency: "usd", + description: "Tickets The event of Wonders", + statement_descriptor_suffix: "Tickets The event of W", + metadata: {kind: "Ticket", event_id: event.id, nonprofit_id: nonprofit.id}, + transfer_data: {destination: "test_acct_1"}, + on_behalf_of: "test_acct_1"}, {stripe_version: "2019-09-09"}).and_wrap_original { |m, *args| + a = m.call(*args) + stripe_charge_id = a["id"] + a + } + result = InsertTickets.create(include_valid_token.merge(event_discount_id: event_discount.id).merge(fee_covered: other_elements[:fee_covered], amount: other_elements[:amount])) + tp = result["tickets"][0].ticket_purchase expected = generate_expected_tickets( - {gross_amount: other_elements[:amount], - payment_fee_total: other_elements[:fee], - payment_id: result['payment'].id, - nonprofit: nonprofit, - supporter: supporter, - event: event, - charge_id: result['charge'].id, - stripe_charge_id: stripe_charge_id, - event_discount_id: event_discount.id, - card: card, - tickets: [{ - id: result['tickets'][0]['id'], - quantity: 1, - ticket_level_id: ticket_level.id, - ticket_purchase_id: tp.id, - }, - { - id: result['tickets'][0]['id'], - quantity: 2, - ticket_level_id: ticket_level2.id, - ticket_purchase_id: tp.id, - }]}.merge(other_elements)) - - expect(result['payment'].attributes).to eq expected[:payment] - expect(result['charge'].attributes).to eq expected[:charge] - expect(result['tickets'].map{|i| i.attributes}[0]).to eq expected[:tickets][0] - - return result + {gross_amount: other_elements[:amount], + payment_fee_total: other_elements[:fee], + payment_id: result["payment"].id, + nonprofit: nonprofit, + supporter: supporter, + event: event, + charge_id: result["charge"].id, + stripe_charge_id: stripe_charge_id, + event_discount_id: event_discount.id, + card: card, + tickets: [{ + id: result["tickets"][0]["id"], + quantity: 1, + ticket_level_id: ticket_level.id, + ticket_purchase_id: tp.id + }, + { + id: result["tickets"][0]["id"], + quantity: 2, + ticket_level_id: ticket_level2.id, + ticket_purchase_id: tp.id + }]}.merge(other_elements) + ) + + expect(result["payment"].attributes).to eq expected[:payment] + expect(result["charge"].attributes).to eq expected[:charge] + expect(result["tickets"].map { |i| i.attributes }[0]).to eq expected[:tickets][0] + + result end end - it 'errors when amount passed is less than expected gross amount' do - expect {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 399)}.to raise_error {|e| + it "errors when amount passed is less than expected gross amount" do + expect { InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, amount: 399) }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :amount}]) expect(e.message).to eq "You authorized a payment of $3.99 but the total value of tickets requested was $16." - }.and not_change { ObjectEvent.count } + }.and not_change { ObjectEvent.count } end - it 'errors where kind == free and positive gross_amount' do - expect {InsertTickets.create(tickets: [{quantity: 1, ticket_level_id: ticket_level.id}], nonprofit_id: nonprofit.id, supporter_id: supporter.id, token: source_token.token, event_id: event.id, 'kind' => 'free', amount: 1600)}.to raise_error {|e| + it "errors where kind == free and positive gross_amount" do + expect { InsertTickets.create(:tickets => [{quantity: 1, ticket_level_id: ticket_level.id}], :nonprofit_id => nonprofit.id, :supporter_id => supporter.id, :token => source_token.token, :event_id => event.id, "kind" => "free", :amount => 1600) }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :kind}]) expect(e.message).to eq "Ticket costs money but you didn't pay." - }.and not_change { ObjectEvent.count } + }.and not_change { ObjectEvent.count } end - end - describe 'when a free ticket is being inserted' do + describe "when a free ticket is being inserted" do before do ticket_level.update_attributes(amount: 0) end let(:ticket) do - InsertTickets.create( + InsertTickets.create( tickets: [{ quantity: 1, ticket_level_id: ticket_level.id }], @@ -568,84 +541,80 @@ def success(other_elements={}) supporter_id: supporter.id, token: source_token.token, event_id: event.id, - kind: 'free', + kind: "free", current_user: user, amount: 0 - )['tickets'].first + )["tickets"].first end - it 'creates the corresponding activity' do - - + it "creates the corresponding activity" do expect(Activity.where(attachment_id: ticket.id).last) .to have_attributes({ - attachment_type: 'Ticket', - kind: 'Ticket', + attachment_type: "Ticket", + kind: "Ticket", nonprofit_id: nonprofit.id, json_data: { - 'event_id' => event.id, - 'quantity' => 1, - 'event_name' => 'The event of Wonders', - 'gross_amount' => 0 + "event_id" => event.id, + "quantity" => 1, + "event_name" => "The event of Wonders", + "gross_amount" => 0 } }) end - it 'adds one ObjectEvent' do + it "adds one ObjectEvent" do expect { ticket }.to change { ObjectEvent.count }.by(1) end - it 'adds one transaction.created event' do - expect { ticket }.to change { ObjectEvent.where(event_type: 'transaction.created').count }.by(1) + it "adds one transaction.created event" do + expect { ticket }.to change { ObjectEvent.where(event_type: "transaction.created").count }.by(1) end - it 'adds one Transaction' do - expect { ticket }.to change { Transaction.count}.by(1) + it "adds one Transaction" do + expect { ticket }.to change { Transaction.count }.by(1) end - end end - describe 'generate_bid_ids' do + describe "generate_bid_ids" do let(:event) { create(:event) } subject { InsertTickets.generate_bid_ids(event.id, ticket_data) } - let(:ticket_data) { [{ quantity: 1, ticket_level_id: 1 }] } + let(:ticket_data) { [{quantity: 1, ticket_level_id: 1}] } - context 'when there are no tickets yet' do - it 'the bid_id starts at 1' do - expect(subject.first['bid_id']).to eq(1) + context "when there are no tickets yet" do + it "the bid_id starts at 1" do + expect(subject.first["bid_id"]).to eq(1) end end - context 'when there are some tickets' do + context "when there are some tickets" do let!(:tickets) { [force_create(:ticket, event_id: event.id, bid_id: 1), force_create(:ticket, event_id: event.id, bid_id: 2), force_create(:ticket, event_id: event.id, bid_id: 3)] } - it 'follows creates a bid_id with the next available number' do - expect(subject.first['bid_id']).to eq(4) + it "follows creates a bid_id with the next available number" do + expect(subject.first["bid_id"]).to eq(4) end - context 'when some ticket in the middle is deleted' do + context "when some ticket in the middle is deleted" do before do ticket = Ticket.find_by(bid_id: 2) ticket.destroy end - it 'the next ticket follows the higher bid_id number' do - expect(subject.first['bid_id']).to eq(4) + it "the next ticket follows the higher bid_id number" do + expect(subject.first["bid_id"]).to eq(4) end end - context 'when the last ticket is deleted' do + context "when the last ticket is deleted" do before do ticket = Ticket.find_by(bid_id: 3) ticket.destroy end - it 'the next ticket gets created as the with the destroyed bid_id' do - expect(subject.first['bid_id']).to eq(3) + it "the next ticket gets created as the with the destroyed bid_id" do + expect(subject.first["bid_id"]).to eq(3) end end end end end - diff --git a/spec/lib/interpolation_dictionary_spec.rb b/spec/lib/interpolation_dictionary_spec.rb index 66a6bbb33..2d35e5123 100644 --- a/spec/lib/interpolation_dictionary_spec.rb +++ b/spec/lib/interpolation_dictionary_spec.rb @@ -1,64 +1,62 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe InterpolationDictionary do - - describe ".add_entry" do - it 'accepts when provided a key we are looking for' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) - expect(id.add_entry('NAME', 'Penelope Schultz')).to be_truthy - expect(id.entries).to eq({'NAME' => 'Penelope Schultz'}) + describe ".add_entry" do + it "accepts when provided a key we are looking for" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) + expect(id.add_entry("NAME", "Penelope Schultz")).to be_truthy + expect(id.entries).to eq({"NAME" => "Penelope Schultz"}) end - - it 'rejects when provided an invalid key' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) - expect(id.add_entry('BADKEY', 'Name with Key')).to be_falsy - expect(id.entries).to eq({'NAME' => 'Supporter'}) + + it "rejects when provided an invalid key" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) + expect(id.add_entry("BADKEY", "Name with Key")).to be_falsy + expect(id.entries).to eq({"NAME" => "Supporter"}) end - it 'rejects when provided a value which is empty when santized' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) - expect(id.add_entry('NAME', ' ')).to be_falsy - expect(id.entries).to eq({'NAME' => 'Supporter'}) + it "rejects when provided a value which is empty when santized" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) + expect(id.add_entry("NAME", " ")).to be_falsy + expect(id.entries).to eq({"NAME" => "Supporter"}) end - it 'strips out tags from a value' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) - expect(id.add_entry('NAME', 'Another name
')).to be_truthy - expect(id.entries).to eq({'NAME' => 'Another name '}) + it "strips out tags from a value" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) + expect(id.add_entry("NAME", "Another name
")).to be_truthy + expect(id.entries).to eq({"NAME" => "Another name "}) end - it 'doesnt replace value if nil' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) - expect(id.add_entry('NAME', nil)).to be_falsey - expect(id.entries).to eq({'NAME' => 'Supporter'}) + it "doesnt replace value if nil" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) + expect(id.add_entry("NAME", nil)).to be_falsey + expect(id.entries).to eq({"NAME" => "Supporter"}) end end - describe ".interpolate" do - it 'accepts and strips out bad tags' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) - expect(id.add_entry('NAME', 'Penelope Schultz')).to be_truthy + describe ".interpolate" do + it "accepts and strips out bad tags" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) + expect(id.add_entry("NAME", "Penelope Schultz")).to be_truthy str = id.interpolate("{{NAME}}") - expect(str).to eq 'Penelope Schultz' + expect(str).to eq "Penelope Schultz" end - - it 'replaces the correct variable' do - id = InterpolationDictionary.new({'NAME' => 'Supporter', 'FIRSTNAME' => 'Supporter'}) - expect(id.add_entry('FIRSTNAME', 'Name with Key')).to be_truthy + + it "replaces the correct variable" do + id = InterpolationDictionary.new({"NAME" => "Supporter", "FIRSTNAME" => "Supporter"}) + expect(id.add_entry("FIRSTNAME", "Name with Key")).to be_truthy str = id.interpolate("Dear {{NAME}}, you are appreciated.") - expect(str).to eq 'Dear Supporter, you are appreciated.' + expect(str).to eq "Dear Supporter, you are appreciated." end - it 'returns falsy if final interpolation is empty' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) + it "returns falsy if final interpolation is empty" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) expect(id.interpolate(" ")).to be_falsy end - it 'returns falsy if nil passed to interpolate' do - id = InterpolationDictionary.new({'NAME' => 'Supporter'}) + it "returns falsy if nil passed to interpolate" do + id = InterpolationDictionary.new({"NAME" => "Supporter"}) expect(id.interpolate(nil)).to be_falsy end end - end diff --git a/spec/lib/job_queue_spec.rb b/spec/lib/job_queue_spec.rb index e84c0634b..7580f5f25 100644 --- a/spec/lib/job_queue_spec.rb +++ b/spec/lib/job_queue_spec.rb @@ -2,18 +2,17 @@ require "rails_helper" describe JobQueue do - - let(:klass) { class_double("FakeClass")} - let(:fake_object) { instance_double('FakeClass') } - it 'handles empty args' do + let(:klass) { class_double("FakeClass") } + let(:fake_object) { instance_double("FakeClass") } + it "handles empty args" do expect(klass).to receive(:new).and_return(fake_object) expect(Delayed::Job).to receive(:enqueue).with(fake_object) JobQueue.queue(klass) end - it 'handles other args' do + it "handles other args" do expect(klass).to receive(:new).with(1, 2).and_return(fake_object) expect(Delayed::Job).to receive(:enqueue).with(fake_object) JobQueue.queue(klass, 1, 2) end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/admin_failed_gift_job_spec.rb b/spec/lib/job_types/admin_failed_gift_job_spec.rb index 870134539..67ea490c1 100644 --- a/spec/lib/job_types/admin_failed_gift_job_spec.rb +++ b/spec/lib/job_types/admin_failed_gift_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::AdminFailedGiftJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(AdminMailer).to receive(:notify_failed_gift).with(1,2, 3).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(AdminMailer).to receive(:notify_failed_gift).with(1, 2, 3).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } - job = JobTypes::AdminFailedGiftJob.new(1,2,3) + job = JobTypes::AdminFailedGiftJob.new(1, 2, 3) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/admin_notice_job_spec.rb b/spec/lib/job_types/admin_notice_job_spec.rb index 95c78819d..e41073bf4 100644 --- a/spec/lib/job_types/admin_notice_job_spec.rb +++ b/spec/lib/job_types/admin_notice_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::AdminNoticeJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(GenericMailer).to receive(:admin_notice).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(GenericMailer).to receive(:admin_notice).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::AdminNoticeJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/campaign_creation_followup_job_spec.rb b/spec/lib/job_types/campaign_creation_followup_job_spec.rb index 1f17beb33..4d8e0c5e8 100644 --- a/spec/lib/job_types/campaign_creation_followup_job_spec.rb +++ b/spec/lib/job_types/campaign_creation_followup_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::CampaignCreationFollowupJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(CampaignMailer).to receive(:creation_followup).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(CampaignMailer).to receive(:creation_followup).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::CampaignCreationFollowupJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/campaign_updated_job_spec.rb b/spec/lib/job_types/campaign_updated_job_spec.rb index 7d71a6e6c..cec24fbcc 100644 --- a/spec/lib/job_types/campaign_updated_job_spec.rb +++ b/spec/lib/job_types/campaign_updated_job_spec.rb @@ -1,19 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::CampaignUpdatedJob do - describe '.perform' do - let(:parent_campaign) {create(:campaign_with_things_set_1, summary: 'a new summary')} + describe ".perform" do + let(:parent_campaign) { create(:campaign_with_things_set_1, summary: "a new summary") } - let!(:child_campaign) {create(:campaign_with_things_set_1, - nonprofit_id: parent_campaign.nonprofit.id, - parent_campaign_id: parent_campaign.id, slug: 'another-slug-of-slugs-1')} + let!(:child_campaign) { + create(:campaign_with_things_set_1, + nonprofit_id: parent_campaign.nonprofit.id, + parent_campaign_id: parent_campaign.id, slug: "another-slug-of-slugs-1") + } - let!(:child_campaign_2) {create(:campaign_with_things_set_1, - nonprofit_id: parent_campaign.nonprofit.id, - parent_campaign_id: parent_campaign.id, slug: 'another-slug-of-slugs-2')} + let!(:child_campaign_2) { + create(:campaign_with_things_set_1, + nonprofit_id: parent_campaign.nonprofit.id, + parent_campaign_id: parent_campaign.id, slug: "another-slug-of-slugs-2") + } - it 'schedules the child campaigns to update' do + it "schedules the child campaigns to update" do expect_job_queued.with(JobTypes::ChildCampaignUpdateJob, child_campaign.id) expect_job_queued.with(JobTypes::ChildCampaignUpdateJob, child_campaign_2.id) @@ -21,4 +25,4 @@ job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/child_campaign_update_job_spec.rb b/spec/lib/job_types/child_campaign_update_job_spec.rb index f0b50ee2d..c55e70741 100644 --- a/spec/lib/job_types/child_campaign_update_job_spec.rb +++ b/spec/lib/job_types/child_campaign_update_job_spec.rb @@ -1,21 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ChildCampaignUpdateJob do - describe '.perform' do - let(:parent_campaign) {create(:campaign_with_things_set_1, summary: 'a new summary')} + describe ".perform" do + let(:parent_campaign) { create(:campaign_with_things_set_1, summary: "a new summary") } - let!(:child_campaign) {create(:campaign_with_things_set_1, - nonprofit_id: parent_campaign.nonprofit.id, - parent_campaign_id: parent_campaign.id, slug: 'another-slug-of-slugs-1')} + let!(:child_campaign) { + create(:campaign_with_things_set_1, + nonprofit_id: parent_campaign.nonprofit.id, + parent_campaign_id: parent_campaign.id, slug: "another-slug-of-slugs-1") + } - it 'updates the child from the parent' do + it "updates the child from the parent" do job = JobTypes::ChildCampaignUpdateJob.new(child_campaign.id) job.perform child_campaign.reload - + expect(child_campaign.summary).to eq "a new summary" end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/donation_payment_create_job_spec.rb b/spec/lib/job_types/donation_payment_create_job_spec.rb index 064129828..d45d11c82 100644 --- a/spec/lib/job_types/donation_payment_create_job_spec.rb +++ b/spec/lib/job_types/donation_payment_create_job_spec.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::DonationPaymentCreateJob do - describe '.perform', pending: true do + describe ".perform", pending: true do end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/donor_direct_debit_notification_job_spec.rb b/spec/lib/job_types/donor_direct_debit_notification_job_spec.rb index 5592a839a..d420ecfed 100644 --- a/spec/lib/job_types/donor_direct_debit_notification_job_spec.rb +++ b/spec/lib/job_types/donor_direct_debit_notification_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::DonorDirectDebitNotificationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:donor_direct_debit_notification).with(1,2 ).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:donor_direct_debit_notification).with(1, 2).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::DonorDirectDebitNotificationJob.new(1, 2) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/donor_failed_recurring_donation_job_spec.rb b/spec/lib/job_types/donor_failed_recurring_donation_job_spec.rb index eda22880d..3b0783714 100644 --- a/spec/lib/job_types/donor_failed_recurring_donation_job_spec.rb +++ b/spec/lib/job_types/donor_failed_recurring_donation_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::DonorFailedRecurringDonationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:donor_failed_recurring_donation).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:donor_failed_recurring_donation).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::DonorFailedRecurringDonationJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/donor_payment_notification_job_spec.rb b/spec/lib/job_types/donor_payment_notification_job_spec.rb index 0291bcb48..d8c16babd 100644 --- a/spec/lib/job_types/donor_payment_notification_job_spec.rb +++ b/spec/lib/job_types/donor_payment_notification_job_spec.rb @@ -1,12 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::DonorPaymentNotificationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:donor_payment_notification).with(1,2,3).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:donor_payment_notification).with(1, 2, 3).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } - job = JobTypes::DonorPaymentNotificationJob.new(1,2,3) + job = JobTypes::DonorPaymentNotificationJob.new(1, 2, 3) job.perform end end diff --git a/spec/lib/job_types/donor_recurring_donation_change_amount_job_spec.rb b/spec/lib/job_types/donor_recurring_donation_change_amount_job_spec.rb index 3480a1cb8..595e74a8d 100644 --- a/spec/lib/job_types/donor_recurring_donation_change_amount_job_spec.rb +++ b/spec/lib/job_types/donor_recurring_donation_change_amount_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::DonorRecurringDonationChangeAmountJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:donor_recurring_donation_change_amount).with(1, 100).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:donor_recurring_donation_change_amount).with(1, 100).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::DonorRecurringDonationChangeAmountJob.new(1, 100) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/donor_refund_notification_job_spec.rb b/spec/lib/job_types/donor_refund_notification_job_spec.rb index d34e00bb1..54ea9ee3a 100644 --- a/spec/lib/job_types/donor_refund_notification_job_spec.rb +++ b/spec/lib/job_types/donor_refund_notification_job_spec.rb @@ -1,11 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::DonorRefundNotificationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(UserMailer).to receive(:refund_receipt).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} - + describe ".perform" do + it "calls the correct active mailer" do + expect(UserMailer).to receive(:refund_receipt).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::DonorRefundNotificationJob.new(1) job.perform diff --git a/spec/lib/job_types/email_job_spec.rb b/spec/lib/job_types/email_job_spec.rb index 0c3decc71..ad824a33c 100644 --- a/spec/lib/job_types/email_job_spec.rb +++ b/spec/lib/job_types/email_job_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::EmailJob do - describe '.reschedule_at' do - it '50 attempts takes about 24 hours' do + describe ".reschedule_at" do + it "50 attempts takes about 24 hours" do job = JobTypes::EmailJob.new - initial_time = Time.utc(2020,5,5) + initial_time = Time.utc(2020, 5, 5) end_time = initial_time + 1.day current_time = initial_time - 50.times.map{|i| i+1}.each{|i| + 50.times.map { |i| i + 1 }.each { |i| current_time = job.reschedule_at(current_time, i) } expect(current_time).to be_between(end_time - 5.minutes, end_time + 5.minutes) diff --git a/spec/lib/job_types/event_creation_followup_job_spec.rb b/spec/lib/job_types/event_creation_followup_job_spec.rb index acfd716a2..7e5ff7ec4 100644 --- a/spec/lib/job_types/event_creation_followup_job_spec.rb +++ b/spec/lib/job_types/event_creation_followup_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::EventCreationFollowupJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(EventMailer).to receive(:creation_followup).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(EventMailer).to receive(:creation_followup).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::EventCreationFollowupJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_payment_completed_job_spec.rb b/spec/lib/job_types/export_payment_completed_job_spec.rb index 46574c221..16f8f71f2 100644 --- a/spec/lib/job_types/export_payment_completed_job_spec.rb +++ b/spec/lib/job_types/export_payment_completed_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportPaymentCompletedJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(ExportMailer).to receive(:export_payments_completed_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(ExportMailer).to receive(:export_payments_completed_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportPaymentCompletedJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_payment_failed_job_spec.rb b/spec/lib/job_types/export_payment_failed_job_spec.rb index 4a0852541..259413196 100644 --- a/spec/lib/job_types/export_payment_failed_job_spec.rb +++ b/spec/lib/job_types/export_payment_failed_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportPaymentFailedJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(ExportMailer).to receive(:export_payments_failed_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(ExportMailer).to receive(:export_payments_failed_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportPaymentFailedJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_recurring_donations_completed_job_spec.rb b/spec/lib/job_types/export_recurring_donations_completed_job_spec.rb index a322ddbfc..21c41fc07 100644 --- a/spec/lib/job_types/export_recurring_donations_completed_job_spec.rb +++ b/spec/lib/job_types/export_recurring_donations_completed_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportRecurringDonationsCompletedJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(ExportMailer).to receive(:export_recurring_donations_completed_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(ExportMailer).to receive(:export_recurring_donations_completed_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportRecurringDonationsCompletedJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_recurring_donations_failed_job_spec.rb b/spec/lib/job_types/export_recurring_donations_failed_job_spec.rb index 523a0e725..3a7d740d0 100644 --- a/spec/lib/job_types/export_recurring_donations_failed_job_spec.rb +++ b/spec/lib/job_types/export_recurring_donations_failed_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportRecurringDonationsFailedJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(ExportMailer).to receive(:export_recurring_donations_failed_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(ExportMailer).to receive(:export_recurring_donations_failed_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportRecurringDonationsFailedJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_supporter_notes_completed_spec.rb b/spec/lib/job_types/export_supporter_notes_completed_spec.rb index b07210673..c95520720 100644 --- a/spec/lib/job_types/export_supporter_notes_completed_spec.rb +++ b/spec/lib/job_types/export_supporter_notes_completed_spec.rb @@ -1,14 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportSupporterNotesCompletedJob do - describe '.perform' do - it 'calls the correct active mailer' do + describe ".perform" do + it "calls the correct active mailer" do input = 1 - expect(ExportMailer).to receive(:export_supporter_notes_completed_notification).with(input).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + expect(ExportMailer).to receive(:export_supporter_notes_completed_notification).with(input).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportSupporterNotesCompletedJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_supporter_notes_failed_spec.rb b/spec/lib/job_types/export_supporter_notes_failed_spec.rb index d9460e06c..58971b609 100644 --- a/spec/lib/job_types/export_supporter_notes_failed_spec.rb +++ b/spec/lib/job_types/export_supporter_notes_failed_spec.rb @@ -1,14 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportSupporterNotesFailedJob do - describe '.perform' do - it 'calls the correct active mailer' do - input = 1 - expect(ExportMailer).to receive(:export_supporter_notes_failed_notification).with(input).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + input = 1 + expect(ExportMailer).to receive(:export_supporter_notes_failed_notification).with(input).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportSupporterNotesFailedJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_supporters_completed_job_spec.rb b/spec/lib/job_types/export_supporters_completed_job_spec.rb index b8f79aeb6..d159db513 100644 --- a/spec/lib/job_types/export_supporters_completed_job_spec.rb +++ b/spec/lib/job_types/export_supporters_completed_job_spec.rb @@ -1,13 +1,17 @@ -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportSupportersCompletedJob do - describe '.perform' do - it 'calls the correct active mailer' do + describe ".perform" do + it "calls the correct active mailer" do input = 1 - expect(ExportMailer).to receive(:export_supporters_completed_notification).with(input).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + expect(ExportMailer).to receive(:export_supporters_completed_notification).with(input).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportSupportersCompletedJob.new(input) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/export_supporters_failed_job_spec.rb b/spec/lib/job_types/export_supporters_failed_job_spec.rb index b1b57d112..99353440f 100644 --- a/spec/lib/job_types/export_supporters_failed_job_spec.rb +++ b/spec/lib/job_types/export_supporters_failed_job_spec.rb @@ -1,13 +1,17 @@ -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ExportSupportersFailedJob do - describe '.perform' do - it 'calls the correct active mailer' do + describe ".perform" do + it "calls the correct active mailer" do input = 1 - expect(ExportMailer).to receive(:export_supporters_failed_notification).with(input).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + expect(ExportMailer).to receive(:export_supporters_failed_notification).with(input).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ExportSupportersFailedJob.new(input) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/generic_mail_job_spec.rb b/spec/lib/job_types/generic_mail_job_spec.rb index 58cec78e6..12176675f 100644 --- a/spec/lib/job_types/generic_mail_job_spec.rb +++ b/spec/lib/job_types/generic_mail_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::GenericMailJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(GenericMailer).to receive(:generic_mail).with(1,2,3,4,5,6).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(GenericMailer).to receive(:generic_mail).with(1, 2, 3, 4, 5, 6).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } - job = JobTypes::GenericMailJob.new(1,2,3,4,5,6) + job = JobTypes::GenericMailJob.new(1, 2, 3, 4, 5, 6) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/import_complete_notification_job_spec.rb b/spec/lib/job_types/import_complete_notification_job_spec.rb index 51b2c27dd..72e151db3 100644 --- a/spec/lib/job_types/import_complete_notification_job_spec.rb +++ b/spec/lib/job_types/import_complete_notification_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::ImportCompleteNotificationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(ImportMailer).to receive(:import_completed_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(ImportMailer).to receive(:import_completed_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::ImportCompleteNotificationJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_admin_existing_invite_job_spec.rb b/spec/lib/job_types/nonprofit_admin_existing_invite_job_spec.rb index fc1fed458..5da64d165 100644 --- a/spec/lib/job_types/nonprofit_admin_existing_invite_job_spec.rb +++ b/spec/lib/job_types/nonprofit_admin_existing_invite_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitAdminExistingInviteJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitAdminMailer).to receive(:existing_invite).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitAdminMailer).to receive(:existing_invite).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitAdminExistingInviteJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_admin_new_invite_job_spec.rb b/spec/lib/job_types/nonprofit_admin_new_invite_job_spec.rb index 0d8b55957..f65ce64fc 100644 --- a/spec/lib/job_types/nonprofit_admin_new_invite_job_spec.rb +++ b/spec/lib/job_types/nonprofit_admin_new_invite_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitAdminNewInviteJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitAdminMailer).to receive(:new_invite).with(1,2).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitAdminMailer).to receive(:new_invite).with(1, 2).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } - job = JobTypes::NonprofitAdminNewInviteJob.new(1,2) + job = JobTypes::NonprofitAdminNewInviteJob.new(1, 2) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_admin_supporter_fundraiser_job_spec.rb b/spec/lib/job_types/nonprofit_admin_supporter_fundraiser_job_spec.rb index 2c50a3eae..72130ef9a 100644 --- a/spec/lib/job_types/nonprofit_admin_supporter_fundraiser_job_spec.rb +++ b/spec/lib/job_types/nonprofit_admin_supporter_fundraiser_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitAdminSupporterFundraiserJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitAdminMailer).to receive(:supporter_fundraiser).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitAdminMailer).to receive(:supporter_fundraiser).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitAdminSupporterFundraiserJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_create_job_spec.rb b/spec/lib/job_types/nonprofit_create_job_spec.rb index 1d4da3db5..43aa49fdc 100644 --- a/spec/lib/job_types/nonprofit_create_job_spec.rb +++ b/spec/lib/job_types/nonprofit_create_job_spec.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitCreateJob do - describe '.perform', pending: true do + describe ".perform", pending: true do end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_failed_recurring_donation_job_spec.rb b/spec/lib/job_types/nonprofit_failed_recurring_donation_job_spec.rb index d1422cd56..f64624aa5 100644 --- a/spec/lib/job_types/nonprofit_failed_recurring_donation_job_spec.rb +++ b/spec/lib/job_types/nonprofit_failed_recurring_donation_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitFailedRecurringDonationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:nonprofit_failed_recurring_donation).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:nonprofit_failed_recurring_donation).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitFailedRecurringDonationJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_first_donation_payment_job_spec.rb b/spec/lib/job_types/nonprofit_first_donation_payment_job_spec.rb index 33dd7275f..d800c354b 100644 --- a/spec/lib/job_types/nonprofit_first_donation_payment_job_spec.rb +++ b/spec/lib/job_types/nonprofit_first_donation_payment_job_spec.rb @@ -1,35 +1,34 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitFirstDonationPaymentJob do include_context :shared_donation_charge_context - describe '.perform' do + describe ".perform" do + let(:donation_without_np) { force_create(:donation) } + let(:donation_without_charge) { force_create(:donation, nonprofit: nonprofit) } + let(:charge) { force_create(:charge, nonprofit: nonprofit, donation: donation) } + let(:donation) { force_create(:donation, nonprofit: nonprofit) } + let(:misc_np_infos_no_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit) } - let(:donation_without_np) { force_create(:donation)} - let(:donation_without_charge) { force_create(:donation, nonprofit: nonprofit)} - let(:charge) {force_create(:charge, nonprofit: nonprofit, donation: donation)} - let(:donation) {force_create(:donation, nonprofit: nonprofit)} - let(:misc_np_infos_no_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit)} + let(:misc_np_infos_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit, first_charge_email_sent: true) } - let(:misc_np_infos_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit, first_charge_email_sent:true)} - - it 'does not send email if nonprofit isnt found' do + it "does not send email if nonprofit isnt found" do expect_job_not_queued JobTypes::NonprofitFirstDonationPaymentJob.new(donation_without_np.id).perform end - it 'does not send email if charge isnt found' do + it "does not send email if charge isnt found" do expect_job_not_queued JobTypes::NonprofitFirstDonationPaymentJob.new(donation_without_charge.id).perform end - it 'does not send email if nonprofit is found but first charge already sent' do + it "does not send email if nonprofit is found but first charge already sent" do misc_np_infos_first_charge_sent expect_job_not_queued JobTypes::NonprofitFirstDonationPaymentJob.new(donation_without_np.id).perform end - it 'sends email when everything correct' do + it "sends email when everything correct" do misc_np_infos_no_first_charge_sent expect_job_queued.with(JobTypes::NonprofitFirstChargeEmailJob, nonprofit.id) charge @@ -38,4 +37,4 @@ expect(misc_np_infos_no_first_charge_sent.first_charge_email_sent).to be true end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_first_ticket_payment_job_spec.rb b/spec/lib/job_types/nonprofit_first_ticket_payment_job_spec.rb index f63dc2eed..e3f1d31a8 100644 --- a/spec/lib/job_types/nonprofit_first_ticket_payment_job_spec.rb +++ b/spec/lib/job_types/nonprofit_first_ticket_payment_job_spec.rb @@ -1,36 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitFirstTicketPaymentJob do include_context :shared_donation_charge_context - describe '.perform' do + describe ".perform" do + let(:ticket_without_np) { force_create(:ticket, charge: charge) } + let(:ticket_without_charge) { force_create(:ticket, nonprofit: nonprofit) } + let(:charge) { force_create(:charge, nonprofit: nonprofit) } + let(:ticket) { force_create(:ticket, charge: charge, event: event) } + let(:event) { force_create(:event, nonprofit: nonprofit) } + let(:misc_np_infos_no_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit) } - let(:ticket_without_np) { force_create(:ticket, charge:charge)} - let(:ticket_without_charge) { force_create(:ticket, nonprofit: nonprofit)} - let(:charge) {force_create(:charge, nonprofit: nonprofit)} - let(:ticket) { force_create(:ticket, charge: charge, event: event)} - let(:event) {force_create(:event, nonprofit: nonprofit)} - let(:misc_np_infos_no_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit)} + let(:misc_np_infos_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit, first_charge_email_sent: true) } - let(:misc_np_infos_first_charge_sent) { force_create(:miscellaneous_np_info, nonprofit: nonprofit, first_charge_email_sent:true)} - - it 'does not send email if nonprofit isnt found' do + it "does not send email if nonprofit isnt found" do expect_job_not_queued JobTypes::NonprofitFirstTicketPaymentJob.new([ticket_without_np.id]).perform end - it 'does not send email if charge isnt found' do + it "does not send email if charge isnt found" do expect_job_not_queued JobTypes::NonprofitFirstTicketPaymentJob.new([ticket_without_charge.id]).perform end - it 'does not send email if nonprofit is found but first charge already sent' do + it "does not send email if nonprofit is found but first charge already sent" do misc_np_infos_first_charge_sent expect_job_not_queued JobTypes::NonprofitFirstTicketPaymentJob.new([ticket.id]).perform end - it 'sends email when everything correct' do + it "sends email when everything correct" do misc_np_infos_no_first_charge_sent expect_job_queued.with(JobTypes::NonprofitFirstChargeEmailJob, nonprofit.id) charge @@ -39,4 +38,4 @@ expect(misc_np_infos_no_first_charge_sent.first_charge_email_sent).to be true end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_new_bank_account_job_spec.rb b/spec/lib/job_types/nonprofit_new_bank_account_job_spec.rb index 0fbf434ec..cb9be3239 100644 --- a/spec/lib/job_types/nonprofit_new_bank_account_job_spec.rb +++ b/spec/lib/job_types/nonprofit_new_bank_account_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitNewBankAccountJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitMailer).to receive(:new_bank_account_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitMailer).to receive(:new_bank_account_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitNewBankAccountJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_payment_notification_job_spec.rb b/spec/lib/job_types/nonprofit_payment_notification_job_spec.rb index 2e2a9d434..404c1b9df 100644 --- a/spec/lib/job_types/nonprofit_payment_notification_job_spec.rb +++ b/spec/lib/job_types/nonprofit_payment_notification_job_spec.rb @@ -1,17 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitPaymentNotificationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:nonprofit_payment_notification).with(1, 2, nil).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:nonprofit_payment_notification).with(1, 2, nil).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } - job = JobTypes::NonprofitPaymentNotificationJob.new(1,2) + job = JobTypes::NonprofitPaymentNotificationJob.new(1, 2) job.perform end - it 'calls the correct active mailer, with user id' do - expect(DonationMailer).to receive(:nonprofit_payment_notification).with(1, 2, 3).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + it "calls the correct active mailer, with user id" do + expect(DonationMailer).to receive(:nonprofit_payment_notification).with(1, 2, 3).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitPaymentNotificationJob.new(1, 2, 3) job.perform diff --git a/spec/lib/job_types/nonprofit_pending_payout_job_spec.rb b/spec/lib/job_types/nonprofit_pending_payout_job_spec.rb index 44fed9cbd..23a842669 100644 --- a/spec/lib/job_types/nonprofit_pending_payout_job_spec.rb +++ b/spec/lib/job_types/nonprofit_pending_payout_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitPendingPayoutJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitMailer).to receive(:pending_payout_notification).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitMailer).to receive(:pending_payout_notification).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitPendingPayoutJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_recurring_donation_cancellation_job_spec.rb b/spec/lib/job_types/nonprofit_recurring_donation_cancellation_job_spec.rb index 2a85dd5b2..d30d95191 100644 --- a/spec/lib/job_types/nonprofit_recurring_donation_cancellation_job_spec.rb +++ b/spec/lib/job_types/nonprofit_recurring_donation_cancellation_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitRecurringDonationCancellationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:nonprofit_recurring_donation_cancellation).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:nonprofit_recurring_donation_cancellation).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitRecurringDonationCancellationJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_recurring_donation_change_amount_job_spec.rb b/spec/lib/job_types/nonprofit_recurring_donation_change_amount_job_spec.rb index fc3867896..ff9c3417f 100644 --- a/spec/lib/job_types/nonprofit_recurring_donation_change_amount_job_spec.rb +++ b/spec/lib/job_types/nonprofit_recurring_donation_change_amount_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitRecurringDonationChangeAmountJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(DonationMailer).to receive(:nonprofit_recurring_donation_change_amount).with(1, 100).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(DonationMailer).to receive(:nonprofit_recurring_donation_change_amount).with(1, 100).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitRecurringDonationChangeAmountJob.new(1, 100) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/nonprofit_refund_notification_job_spec.rb b/spec/lib/job_types/nonprofit_refund_notification_job_spec.rb index 0c5b7384c..87b5fed70 100644 --- a/spec/lib/job_types/nonprofit_refund_notification_job_spec.rb +++ b/spec/lib/job_types/nonprofit_refund_notification_job_spec.rb @@ -1,19 +1,25 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitRefundNotificationJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitMailer).to receive(:refund_notification).with(1, nil).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} - + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitMailer).to receive(:refund_notification).with(1, nil).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitRefundNotificationJob.new(1) job.perform end - it 'calls the correct active mailer' do - expect(NonprofitMailer).to receive(:refund_notification).with(1, 2).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} - + it "calls the correct active mailer" do + expect(NonprofitMailer).to receive(:refund_notification).with(1, 2).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitRefundNotificationJob.new(1, 2) job.perform diff --git a/spec/lib/job_types/nonprofit_welcome_job_spec.rb b/spec/lib/job_types/nonprofit_welcome_job_spec.rb index 7fa0839cd..b3b2389c3 100644 --- a/spec/lib/job_types/nonprofit_welcome_job_spec.rb +++ b/spec/lib/job_types/nonprofit_welcome_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::NonprofitWelcomeJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(NonprofitMailer).to receive(:welcome).with(1).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(NonprofitMailer).to receive(:welcome).with(1).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::NonprofitWelcomeJob.new(1) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/refund_created_job_spec.rb b/spec/lib/job_types/refund_created_job_spec.rb index 6f7a5d4b4..5649e1d58 100644 --- a/spec/lib/job_types/refund_created_job_spec.rb +++ b/spec/lib/job_types/refund_created_job_spec.rb @@ -1,15 +1,15 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::RefundCreatedJob do - describe '.perform' do - let(:refund) {force_create(:refund)} - let(:job) { JobTypes::RefundCreatedJob.new(refund).perform} + describe ".perform" do + let(:refund) { force_create(:refund) } + let(:job) { JobTypes::RefundCreatedJob.new(refund).perform } - it 'sends refund notifications' do + it "sends refund notifications" do expect_job_queued.with(JobTypes::NonprofitRefundNotificationJob, refund.id) expect_job_queued.with(JobTypes::DonorRefundNotificationJob, refund.id) job end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/ticket_mailer_followup_job_spec.rb b/spec/lib/job_types/ticket_mailer_followup_job_spec.rb index ffbbf0065..b6e15037a 100644 --- a/spec/lib/job_types/ticket_mailer_followup_job_spec.rb +++ b/spec/lib/job_types/ticket_mailer_followup_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::TicketMailerFollowupJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(TicketMailer).to receive(:followup).with(1,2 ).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(TicketMailer).to receive(:followup).with(1, 2).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::TicketMailerFollowupJob.new(1, 2) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/job_types/ticket_mailer_receipt_admin_job_spec.rb b/spec/lib/job_types/ticket_mailer_receipt_admin_job_spec.rb index 53962183d..c441b43c9 100644 --- a/spec/lib/job_types/ticket_mailer_receipt_admin_job_spec.rb +++ b/spec/lib/job_types/ticket_mailer_receipt_admin_job_spec.rb @@ -1,13 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper.rb' +require "rails_helper" describe JobTypes::TicketMailerReceiptAdminJob do - describe '.perform' do - it 'calls the correct active mailer' do - expect(TicketMailer).to receive(:receipt_admin).with(1, 2).and_wrap_original{|m, *args| mailer = double('object'); expect(mailer).to receive(:deliver).and_return(nil); mailer} + describe ".perform" do + it "calls the correct active mailer" do + expect(TicketMailer).to receive(:receipt_admin).with(1, 2).and_wrap_original { |m, *args| + mailer = double("object") + expect(mailer).to receive(:deliver).and_return(nil) + mailer + } job = JobTypes::TicketMailerReceiptAdminJob.new(1, 2) job.perform end end -end \ No newline at end of file +end diff --git a/spec/lib/mailchimp_spec.rb b/spec/lib/mailchimp_spec.rb index 8bad345af..c53883746 100644 --- a/spec/lib/mailchimp_spec.rb +++ b/spec/lib/mailchimp_spec.rb @@ -1,231 +1,224 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'webmock/rspec' +require "rails_helper" +require "webmock/rspec" describe Mailchimp do - let(:np) { force_create(:nonprofit)} - let(:user) {force_create(:user)} - let(:tag_master) {force_create(:tag_master, nonprofit: np)} - let(:email_list) {force_create(:email_list, mailchimp_list_id: 'list_id', tag_master: tag_master, nonprofit:np, list_name: "temp")} - let(:drip_email_list) {force_create(:drip_email_list)} - let(:supporter_on_both) { force_create(:supporter, nonprofit:np, email: 'on_BOTH@email.com', name: nil)} - let(:supporter_on_local) { force_create(:supporter, nonprofit:np, email: 'on_local@email.com', name: 'Penelope Rebecca Schultz')} - let(:tag_join) {force_create(:tag_join, tag_master: tag_master, supporter: supporter_on_both)} - let(:tag_join2) {force_create(:tag_join, tag_master: tag_master, supporter: supporter_on_local)} - - let(:active_recurring_donation_1) {force_create(:recurring_donation_base, supporter_id: supporter_on_local.id, start_date: Time.new(2019, 10,12))} - let(:cancelled_recurring_donation_1) {force_create(:recurring_donation_base, supporter_id: supporter_on_local.id, start_date: Time.new(2020,1, 12), active:false)} - let(:active_recurring_donation_2) {force_create(:recurring_donation_base, supporter_id: supporter_on_local.id, start_date: Time.new(2019, 11, 12))} - - describe '.hard_sync_list' do - let(:ret_val) { [{id: 'on_both', email_address: 'on_both@email.com', - merge_fields: { - F_NAME: 'Penelope Rebecca', - L_NAME: 'Schultz' - } - }, - {id: 'on_mailchimp', email_address: 'on_mailchimp@email.com', - merge_fields: { - F_NAME: 'Penelope Rebecca', - L_NAME: 'Schultz', - RD_URL_1: active_recurring_donation_2, - RD_URL_2: active_recurring_donation_1, - }} - ] - } - - it 'excepts when excepting' do - expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_raise - - expect{ Mailchimp.generate_batch_ops_for_hard_sync(email_list)}.to raise_error - end - - it 'passes without delete' do - tag_join - tag_join2 - email_list - active_recurring_donation_1 - active_recurring_donation_2 - cancelled_recurring_donation_1 - - expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_return(ret_val) - - result = Mailchimp.generate_batch_ops_for_hard_sync(email_list) - - - expect(result).to match( - [{ - method: 'POST', - path: 'lists/list_id/members', - body: an_instance_of(String) - }]) + let(:np) { force_create(:nonprofit) } + let(:user) { force_create(:user) } + let(:tag_master) { force_create(:tag_master, nonprofit: np) } + let(:email_list) { force_create(:email_list, mailchimp_list_id: "list_id", tag_master: tag_master, nonprofit: np, list_name: "temp") } + let(:drip_email_list) { force_create(:drip_email_list) } + let(:supporter_on_both) { force_create(:supporter, nonprofit: np, email: "on_BOTH@email.com", name: nil) } + let(:supporter_on_local) { force_create(:supporter, nonprofit: np, email: "on_local@email.com", name: "Penelope Rebecca Schultz") } + let(:tag_join) { force_create(:tag_join, tag_master: tag_master, supporter: supporter_on_both) } + let(:tag_join2) { force_create(:tag_join, tag_master: tag_master, supporter: supporter_on_local) } + + let(:active_recurring_donation_1) { force_create(:recurring_donation_base, supporter_id: supporter_on_local.id, start_date: Time.new(2019, 10, 12)) } + let(:cancelled_recurring_donation_1) { force_create(:recurring_donation_base, supporter_id: supporter_on_local.id, start_date: Time.new(2020, 1, 12), active: false) } + let(:active_recurring_donation_2) { force_create(:recurring_donation_base, supporter_id: supporter_on_local.id, start_date: Time.new(2019, 11, 12)) } + + describe ".hard_sync_list" do + let(:ret_val) { + [{id: "on_both", email_address: "on_both@email.com", + merge_fields: { + F_NAME: "Penelope Rebecca", + L_NAME: "Schultz" + }}, + {id: "on_mailchimp", email_address: "on_mailchimp@email.com", + merge_fields: { + F_NAME: "Penelope Rebecca", + L_NAME: "Schultz", + RD_URL_1: active_recurring_donation_2, + RD_URL_2: active_recurring_donation_1 + }}] + } + + it "excepts when excepting" do + expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_raise + + expect { Mailchimp.generate_batch_ops_for_hard_sync(email_list) }.to raise_error end - it 'passes with delete' do - tag_join - tag_join2 - email_list - - expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_return(ret_val) - - result = Mailchimp.generate_batch_ops_for_hard_sync(email_list, true) - expect(result).to match([ - { - method: 'POST', - path: 'lists/list_id/members', - body: an_instance_of(String) - }, - { - method: 'DELETE', - path: 'lists/list_id/members/on_mailchimp' - } - ]) - end + it "passes without delete" do + tag_join + tag_join2 + email_list + active_recurring_donation_1 + active_recurring_donation_2 + cancelled_recurring_donation_1 + + expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_return(ret_val) + + result = Mailchimp.generate_batch_ops_for_hard_sync(email_list) + + expect(result).to match( + [{ + method: "POST", + path: "lists/list_id/members", + body: an_instance_of(String) + }] + ) + end + + it "passes with delete" do + tag_join + tag_join2 + email_list + + expect(Mailchimp).to receive(:get_list_mailchimp_subscribers).with(email_list).and_return(ret_val) + + result = Mailchimp.generate_batch_ops_for_hard_sync(email_list, true) + expect(result).to match([ + { + method: "POST", + path: "lists/list_id/members", + body: an_instance_of(String) + }, + { + method: "DELETE", + path: "lists/list_id/members/on_mailchimp" + } + ]) + end + end + + describe ".sync_nonprofit_users" do + let!(:drip_email_list) { create(:drip_email_list_base) } + let!(:user) { create(:user) } + let!(:nonprofit_user) { create(:user_as_nonprofit_associate) } + + before(:each) do + ActiveJob::Base.queue_adapter = :test + end + + it "bulk syncs users that are from a nonprofit" do + Mailchimp.sync_nonprofit_users + expect(MailchimpNonprofitUserAddJob).to have_been_enqueued.with(nonprofit_user, nonprofit_user.roles.first.host) + end + + it 'this tests that using "anything" here actually works as expected (so we know the next spec does what we want)' do + Mailchimp.sync_nonprofit_users + expect(MailchimpNonprofitUserAddJob).to have_been_enqueued.with(nonprofit_user, anything) + end + + it "will NOT include users that doesnt belong to a nonprofit" do + Mailchimp.sync_nonprofit_users + expect(MailchimpNonprofitUserAddJob).to_not have_been_enqueued.with(user, anything) + end + end + + describe ".create_nonprofit_user_subscribe_body" do + let(:nonprofit) { create(:nonprofit) } + + it "creates nonprofit user subscriber" do + expect(Mailchimp.create_nonprofit_user_subscribe_body(nonprofit, user)).to match({ + "email_address" => user.email, + "status" => "subscribed", + "merge_fields" => { + "NP_ID" => nonprofit.id, + "NP_SUPP" => 0, + "FNAME" => "" + } + }) + end + end + + describe ".create_subscribe_body" do + describe "names" do + it "has provides the F_NAME and L_NAME when there" do + expect(Mailchimp.create_subscribe_body(supporter_on_local)).to match({ + "email_address" => supporter_on_local.email, + "status" => "subscribed", + "merge_fields" => { + "F_NAME" => "Penelope Rebecca", + "L_NAME" => "Schultz" + } + + }) + end + + it "provides null F_NAME and L_NAME when not there" do + expect(Mailchimp.create_subscribe_body(supporter_on_both)).to match({ + "email_address" => supporter_on_both.email, + "status" => "subscribed", + "merge_fields" => { + "F_NAME" => nil, + "L_NAME" => nil + } + }) + end + end + + describe "recurring donation urls" do + it "adds a single RD_URL when theres a single active RD" do + active_recurring_donation_1 + cancelled_recurring_donation_1 + expect(Mailchimp.create_subscribe_body(supporter_on_local)).to match({ + "email_address" => supporter_on_local.email, + "status" => "subscribed", + "merge_fields" => { + "F_NAME" => "Penelope Rebecca", + "L_NAME" => "Schultz", + "RD_URL_1" => "http://us.commitchange.com/recurring_donations/#{active_recurring_donation_1.id}/edit?t=#{active_recurring_donation_1.edit_token}" + } + + }) + end + + it "adds a second RD_URL when theres a second active RD" do + active_recurring_donation_1 + active_recurring_donation_2 + cancelled_recurring_donation_1 + expect(Mailchimp.create_subscribe_body(supporter_on_local)).to match({ + "email_address" => supporter_on_local.email, + "status" => "subscribed", + "merge_fields" => { + "F_NAME" => "Penelope Rebecca", + "L_NAME" => "Schultz", + "RD_URL_1" => "http://us.commitchange.com/recurring_donations/#{active_recurring_donation_2.id}/edit?t=#{active_recurring_donation_2.edit_token}", + "RD_URL_2" => "http://us.commitchange.com/recurring_donations/#{active_recurring_donation_1.id}/edit?t=#{active_recurring_donation_1.edit_token}" + } + + }) + end + end end - describe '.sync_nonprofit_users' do - let!(:drip_email_list) {create(:drip_email_list_base)} - let!(:user) {create(:user)} - let!(:nonprofit_user) {create(:user_as_nonprofit_associate)} - - before(:each) do - ActiveJob::Base.queue_adapter = :test - end - - it 'bulk syncs users that are from a nonprofit' do - Mailchimp.sync_nonprofit_users - expect(MailchimpNonprofitUserAddJob).to have_been_enqueued.with(nonprofit_user, nonprofit_user.roles.first.host) - end - - it 'this tests that using "anything" here actually works as expected (so we know the next spec does what we want)' do - Mailchimp.sync_nonprofit_users - expect(MailchimpNonprofitUserAddJob).to have_been_enqueued.with( nonprofit_user, anything) - end - - it 'will NOT include users that doesnt belong to a nonprofit' do - Mailchimp.sync_nonprofit_users - expect(MailchimpNonprofitUserAddJob).to_not have_been_enqueued.with(user, anything) - end - - end - - describe '.create_nonprofit_user_subscribe_body' do - let(:nonprofit) { create(:nonprofit)} - - it 'creates nonprofit user subscriber' do - expect(Mailchimp.create_nonprofit_user_subscribe_body(nonprofit, user)).to match({ - 'email_address' => user.email, - 'status' => 'subscribed', - 'merge_fields' => { - 'NP_ID' => nonprofit.id, - 'NP_SUPP' => 0, - 'FNAME' => "", - } - }) - end - - end - - - - describe '.create_subscribe_body' do - - describe 'names' do - it 'has provides the F_NAME and L_NAME when there' do - expect(Mailchimp.create_subscribe_body(supporter_on_local)).to match({ - 'email_address' => supporter_on_local.email, - 'status' => 'subscribed', - 'merge_fields' => { - 'F_NAME' => "Penelope Rebecca", - 'L_NAME' => "Schultz" - } - - }) - end - - it 'provides null F_NAME and L_NAME when not there' do - expect(Mailchimp.create_subscribe_body(supporter_on_both)).to match({ - 'email_address' => supporter_on_both.email, - 'status' => 'subscribed', - 'merge_fields' => { - 'F_NAME' => nil, - 'L_NAME' => nil, - } - }) - end - end - - describe 'recurring donation urls' do - - it 'adds a single RD_URL when theres a single active RD' do - active_recurring_donation_1 - cancelled_recurring_donation_1 - expect(Mailchimp.create_subscribe_body(supporter_on_local)).to match( { - 'email_address' => supporter_on_local.email, - 'status' => 'subscribed', - 'merge_fields' => { - 'F_NAME' => "Penelope Rebecca", - 'L_NAME' => "Schultz", - 'RD_URL_1' => "http://us.commitchange.com/recurring_donations/#{active_recurring_donation_1.id}/edit?t=#{active_recurring_donation_1.edit_token}", - } - - }) - end - - it 'adds a second RD_URL when theres a second active RD' do - active_recurring_donation_1 - active_recurring_donation_2 - cancelled_recurring_donation_1 - expect(Mailchimp.create_subscribe_body(supporter_on_local)).to match({ - 'email_address' => supporter_on_local.email, - 'status' => 'subscribed', - 'merge_fields' => { - 'F_NAME' => "Penelope Rebecca", - 'L_NAME' => "Schultz", - 'RD_URL_1' => "http://us.commitchange.com/recurring_donations/#{active_recurring_donation_2.id}/edit?t=#{active_recurring_donation_2.edit_token}", - 'RD_URL_2' => "http://us.commitchange.com/recurring_donations/#{active_recurring_donation_1.id}/edit?t=#{active_recurring_donation_1.edit_token}" } - - }) - end - - end - end - - describe '.get_emails_for_supporter_ids' do - let(:nonprofit) { create(:nonprofit)} - it 'does not include emails for supporters with nil as email' do - supporter = create(:supporter, nonprofit: nonprofit, email: nil) - expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to be_empty - end - - it 'does not include emails for supporters with zero length string as email' do - supporter = create(:supporter, nonprofit: nonprofit, email: '') - expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to be_empty - end - - it 'does not include emails for supporters with blank string as email' do - supporter = create(:supporter, nonprofit: nonprofit, email: ' ') - expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to be_empty - end - - it 'includes email for supporter with email' do - supporter = create(:supporter, nonprofit: nonprofit, email: 'an@email.com') - expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to eq ['an@email.com'] - end - end - - describe '.signup' do - it 'send signup' do - list = create(:email_list_base, nonprofit: np) - stub = stub_request(:put, list.base_uri + "/lists/#{list.mailchimp_list_id}/members").with( - body: hash_including({ - 'email_address' => supporter_on_local.email, - 'status' => 'subscribed', - }) - ) - - Mailchimp.signup(supporter_on_local, list) - - expect(stub).to have_been_requested - end - end + describe ".get_emails_for_supporter_ids" do + let(:nonprofit) { create(:nonprofit) } + it "does not include emails for supporters with nil as email" do + supporter = create(:supporter, nonprofit: nonprofit, email: nil) + expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to be_empty + end + + it "does not include emails for supporters with zero length string as email" do + supporter = create(:supporter, nonprofit: nonprofit, email: "") + expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to be_empty + end + + it "does not include emails for supporters with blank string as email" do + supporter = create(:supporter, nonprofit: nonprofit, email: " ") + expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to be_empty + end + + it "includes email for supporter with email" do + supporter = create(:supporter, nonprofit: nonprofit, email: "an@email.com") + expect(Mailchimp.get_emails_for_supporter_ids(nonprofit.id, supporter.id)).to eq ["an@email.com"] + end + end + + describe ".signup" do + it "send signup" do + list = create(:email_list_base, nonprofit: np) + stub = stub_request(:put, list.base_uri + "/lists/#{list.mailchimp_list_id}/members").with( + body: hash_including({ + "email_address" => supporter_on_local.email, + "status" => "subscribed" + }) + ) + + Mailchimp.signup(supporter_on_local, list) + + expect(stub).to have_been_requested + end + end end diff --git a/spec/lib/merge_supporters_spec.rb b/spec/lib/merge_supporters_spec.rb index ba154ac4c..7a7f05561 100644 --- a/spec/lib/merge_supporters_spec.rb +++ b/spec/lib/merge_supporters_spec.rb @@ -1,22 +1,21 @@ require "rails_helper" describe MergeSupporters do - - let(:np) {force_create(:nonprofit)} + let(:np) { force_create(:nonprofit) } let(:old_supporter1) { force_create(:supporter, nonprofit: np) } let(:old_supporter2) { force_create(:supporter, nonprofit: np) } let(:old_supporter3) { force_create(:supporter, nonprofit: np) } let(:card) { force_create(:card, holder: old_supporter1) } around(:each) do |e| - StripeMockHelper.mock do + StripeMockHelper.mock do Timecop.freeze(2020, 3, 4) do e.run end end end - - describe '.update_associations' do - #one unique tag for 1 + + describe ".update_associations" do + # one unique tag for 1 # one unique tag for 2 # one common tag on both # @@ -24,28 +23,28 @@ # one unique custom field on 2 # one common field on both and keep the value of the most common - let(:new_supporter) {force_create(:supporter, nonprofit:np)} + let(:new_supporter) { force_create(:supporter, nonprofit: np) } - let(:supporter_note) {force_create(:supporter_note, supporter: old_supporter1, content: "feoatheoiath")} + let(:supporter_note) { force_create(:supporter_note, supporter: old_supporter1, content: "feoatheoiath") } - let(:tag_master) {force_create(:tag_master, nonprofit: np, name: 'something')} - let(:tag_master2) {force_create(:tag_master, nonprofit: np, name: 'something2')} - let(:tag_master3) {force_create(:tag_master, nonprofit: np, name: 'something3')} + let(:tag_master) { force_create(:tag_master, nonprofit: np, name: "something") } + let(:tag_master2) { force_create(:tag_master, nonprofit: np, name: "something2") } + let(:tag_master3) { force_create(:tag_master, nonprofit: np, name: "something3") } - let(:tag_on_1) {force_create(:tag_join, tag_master: tag_master, supporter_id: old_supporter1.id)} - let(:tag_on_2) {force_create(:tag_join, tag_master: tag_master2, supporter_id: old_supporter2.id)} - let(:tag_on_both) {[old_supporter1, old_supporter2].each{|i| force_create(:tag_join, tag_master:tag_master3, supporter_id:i.id)}} + let(:tag_on_1) { force_create(:tag_join, tag_master: tag_master, supporter_id: old_supporter1.id) } + let(:tag_on_2) { force_create(:tag_join, tag_master: tag_master2, supporter_id: old_supporter2.id) } + let(:tag_on_both) { [old_supporter1, old_supporter2].each { |i| force_create(:tag_join, tag_master: tag_master3, supporter_id: i.id) } } - let(:custom_field_master) {force_create(:custom_field_master, nonprofit: np, name: 'cfm1')} - let(:custom_field_master2) {force_create(:custom_field_master, nonprofit: np, name: 'cfm2')} - let(:custom_field_master3) {force_create(:custom_field_master, nonprofit: np, name: 'cfm3')} + let(:custom_field_master) { force_create(:custom_field_master, nonprofit: np, name: "cfm1") } + let(:custom_field_master2) { force_create(:custom_field_master, nonprofit: np, name: "cfm2") } + let(:custom_field_master3) { force_create(:custom_field_master, nonprofit: np, name: "cfm3") } - let(:cfj_on_1) { force_create(:custom_field_join, supporter:old_supporter1, custom_field_master: custom_field_master, value: 'cfj_on_1')} - let(:cfj_on_2) { force_create(:custom_field_join, supporter:old_supporter2, custom_field_master: custom_field_master2, value: 'cfj_on_2')} - let(:cfj_on_3) {force_create(:custom_field_join, supporter:old_supporter1, custom_field_master: custom_field_master3, value: 'old_cfj', created_at: Time.now - 1.day)} - let(:cfj_on_4) {force_create(:custom_field_join, supporter:old_supporter2, custom_field_master: custom_field_master3, value: 'new_cfj', created_at: Time.now + 1.day)} + let(:cfj_on_1) { force_create(:custom_field_join, supporter: old_supporter1, custom_field_master: custom_field_master, value: "cfj_on_1") } + let(:cfj_on_2) { force_create(:custom_field_join, supporter: old_supporter2, custom_field_master: custom_field_master2, value: "cfj_on_2") } + let(:cfj_on_3) { force_create(:custom_field_join, supporter: old_supporter1, custom_field_master: custom_field_master3, value: "old_cfj", created_at: Time.now - 1.day) } + let(:cfj_on_4) { force_create(:custom_field_join, supporter: old_supporter2, custom_field_master: custom_field_master3, value: "new_cfj", created_at: Time.now + 1.day) } - let(:profile) {force_create(:profile)} + let(:profile) { force_create(:profile) } before(:each) do np @@ -56,7 +55,7 @@ card end - it 'merges everything properly with tags and cfjs on both' do + it "merges everything properly with tags and cfjs on both" do tag_on_1 tag_on_2 tag_on_both @@ -64,76 +63,76 @@ cfj_on_2 cfj_on_3 cfj_on_4 - old_supporters = Supporter.where('supporters.id IN (?)',[old_supporter1.id, old_supporter2.id]) + old_supporters = Supporter.where("supporters.id IN (?)", [old_supporter1.id, old_supporter2.id]) MergeSupporters.update_associations(old_supporters, new_supporter, np.id, profile.id) old_supporter1.reload old_supporter2.reload expect(old_supporter1.tag_joins.count).to eq 0 expect(old_supporter2.tag_joins.count).to eq 0 expect(new_supporter.tag_joins.count).to eq 3 - expect(new_supporter.tag_joins.map{|i| i.tag_master}).to contain_exactly(tag_master, tag_master2, tag_master3) + expect(new_supporter.tag_joins.map { |i| i.tag_master }).to contain_exactly(tag_master, tag_master2, tag_master3) expect(old_supporter1.custom_field_joins.count).to eq 0 expect(old_supporter2.custom_field_joins.count).to eq 0 expect(new_supporter.custom_field_joins.count).to eq 3 - expect(new_supporter.custom_field_joins.map{|i| i.custom_field_master}).to contain_exactly(custom_field_master, custom_field_master2, custom_field_master3) + expect(new_supporter.custom_field_joins.map { |i| i.custom_field_master }).to contain_exactly(custom_field_master, custom_field_master2, custom_field_master3) - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master}.value).to eq cfj_on_1.value - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master2}.value).to eq cfj_on_2.value - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master3}.value).to eq cfj_on_4.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master }.value).to eq cfj_on_1.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master2 }.value).to eq cfj_on_2.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master3 }.value).to eq cfj_on_4.value expect(new_supporter.supporter_notes.first.id).to eq supporter_note.id end - it 'merges with tags and cfjs on first' do + it "merges with tags and cfjs on first" do tag_on_1 cfj_on_1 cfj_on_3 - old_supporters = Supporter.where('supporters.id IN (?)',[old_supporter1.id, old_supporter2.id]) + old_supporters = Supporter.where("supporters.id IN (?)", [old_supporter1.id, old_supporter2.id]) MergeSupporters.update_associations(old_supporters, new_supporter, np.id, profile.id) old_supporter1.reload old_supporter2.reload expect(old_supporter1.tag_joins.count).to eq 0 expect(old_supporter2.tag_joins.count).to eq 0 expect(new_supporter.tag_joins.count).to eq 1 - expect(new_supporter.tag_joins.map{|i| i.tag_master}).to contain_exactly(tag_master) + expect(new_supporter.tag_joins.map { |i| i.tag_master }).to contain_exactly(tag_master) expect(old_supporter1.custom_field_joins.count).to eq 0 expect(old_supporter2.custom_field_joins.count).to eq 0 expect(new_supporter.custom_field_joins.count).to eq 2 - expect(new_supporter.custom_field_joins.map{|i| i.custom_field_master}).to contain_exactly(custom_field_master, custom_field_master3) + expect(new_supporter.custom_field_joins.map { |i| i.custom_field_master }).to contain_exactly(custom_field_master, custom_field_master3) - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master}.value).to eq cfj_on_1.value - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master3}.value).to eq cfj_on_3.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master }.value).to eq cfj_on_1.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master3 }.value).to eq cfj_on_3.value expect(new_supporter.supporter_notes.first.id).to eq supporter_note.id end - it 'merges with tags and cfjs on second' do + it "merges with tags and cfjs on second" do tag_on_2 cfj_on_2 cfj_on_4 - old_supporters = Supporter.where('supporters.id IN (?)',[old_supporter1.id, old_supporter2.id]) + old_supporters = Supporter.where("supporters.id IN (?)", [old_supporter1.id, old_supporter2.id]) MergeSupporters.update_associations(old_supporters, new_supporter, np.id, profile.id) old_supporter1.reload old_supporter2.reload expect(old_supporter1.tag_joins.count).to eq 0 expect(old_supporter2.tag_joins.count).to eq 0 expect(new_supporter.tag_joins.count).to eq 1 - expect(new_supporter.tag_joins.map{|i| i.tag_master}).to contain_exactly(tag_master2) + expect(new_supporter.tag_joins.map { |i| i.tag_master }).to contain_exactly(tag_master2) expect(old_supporter1.custom_field_joins.count).to eq 0 expect(old_supporter2.custom_field_joins.count).to eq 0 expect(new_supporter.custom_field_joins.count).to eq 2 - expect(new_supporter.custom_field_joins.map{|i| i.custom_field_master}).to contain_exactly(custom_field_master2, custom_field_master3) + expect(new_supporter.custom_field_joins.map { |i| i.custom_field_master }).to contain_exactly(custom_field_master2, custom_field_master3) - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master2}.value).to eq cfj_on_2.value - expect(new_supporter.custom_field_joins.find{|i| i.custom_field_master == custom_field_master3}.value).to eq cfj_on_4.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master2 }.value).to eq cfj_on_2.value + expect(new_supporter.custom_field_joins.find { |i| i.custom_field_master == custom_field_master3 }.value).to eq cfj_on_4.value expect(new_supporter.supporter_notes.first.id).to eq supporter_note.id end - it 'merges with tags and cfjs on neighter' do - old_supporters = Supporter.where('supporters.id IN (?)',[old_supporter1.id, old_supporter2.id]) + it "merges with tags and cfjs on neighter" do + old_supporters = Supporter.where("supporters.id IN (?)", [old_supporter1.id, old_supporter2.id]) MergeSupporters.update_associations(old_supporters, new_supporter, np.id, profile.id) old_supporter1.reload old_supporter2.reload @@ -141,129 +140,127 @@ expect(old_supporter2.tag_joins.count).to eq 0 expect(new_supporter.tag_joins.count).to eq 0 - expect(old_supporter1.custom_field_joins.count).to eq 0 expect(old_supporter2.custom_field_joins.count).to eq 0 expect(new_supporter.custom_field_joins.count).to eq 0 expect(new_supporter.supporter_notes.first.id).to eq supporter_note.id end - it 'updates the card information on the supporter' do - old_supporters = Supporter.where('supporters.id IN (?)',[old_supporter1.id, old_supporter2.id]) + it "updates the card information on the supporter" do + old_supporters = Supporter.where("supporters.id IN (?)", [old_supporter1.id, old_supporter2.id]) MergeSupporters.update_associations(old_supporters, new_supporter, np.id, profile.id) expect(new_supporter.reload.cards.first).to eq(card.reload) end - it 'updates the supporter information on the card' do - old_supporters = Supporter.where('supporters.id IN (?)',[old_supporter1.id, old_supporter2.id]) + it "updates the supporter information on the card" do + old_supporters = Supporter.where("supporters.id IN (?)", [old_supporter1.id, old_supporter2.id]) MergeSupporters.update_associations(old_supporters, new_supporter, np.id, profile.id) expect(card.reload.holder).to eq(new_supporter.reload) end end - describe '.selected' do - - it 'new supporter is anonymous if any of the old supporters are.' do + describe ".selected" do + it "new supporter is anonymous if any of the old supporters are." do old_supporter1.anonymous = true old_supporter1.save! - result = MergeSupporters.selected({name: 'Penelope Schultz'}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil) + result = MergeSupporters.selected({name: "Penelope Schultz"}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil) expect(result[:json][:anonymous]).to eq true - expect(result[:json][:name]).to eq 'Penelope Schultz' + expect(result[:json][:name]).to eq "Penelope Schultz" expect(result[:json][:nonprofit_id]).to eq np.id end - it 'new supporter is not anonymous if none of the old supporters are' do - result = MergeSupporters.selected({name: 'Penelope Schultz'}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil) + it "new supporter is not anonymous if none of the old supporters are" do + result = MergeSupporters.selected({name: "Penelope Schultz"}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil) expect(result[:json][:anonymous]).to eq false - expect(result[:json][:name]).to eq 'Penelope Schultz' + expect(result[:json][:name]).to eq "Penelope Schultz" expect(result[:json][:nonprofit_id]).to eq np.id end - it 'new supporter matches passed in np even if the merged_data says otherwise' do - result = MergeSupporters.selected({name: 'Penelope Schultz', nonprofit_id: 3333333}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil) + it "new supporter matches passed in np even if the merged_data says otherwise" do + result = MergeSupporters.selected({name: "Penelope Schultz", nonprofit_id: 3333333}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil) expect(result[:json][:anonymous]).to eq false expect(result[:json][:nonprofit_id]).to eq np.id - expect(result[:json][:name]).to eq 'Penelope Schultz' + expect(result[:json][:name]).to eq "Penelope Schultz" end - context 'skip_conflicting_custom_fields flag' do - context 'when true' do - context 'when custom fields are conflicting' do - it 'returns the supporters that could not be merged' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'bar') - result = MergeSupporters.selected({name: 'Penelope Schultz'}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, true) + context "skip_conflicting_custom_fields flag" do + context "when true" do + context "when custom fields are conflicting" do + it "returns the supporters that could not be merged" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "bar") + result = MergeSupporters.selected({name: "Penelope Schultz"}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, true) expect(result[:json]).to match_array([old_supporter1.id, old_supporter2.id]) expect(result[:status]).to eq(:failure) end end - context 'when custom fields are not conflicting' do - it 'merges' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - result = MergeSupporters.selected({name: 'Penelope Schultz'}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, true) - expect(result[:json].custom_field_joins.pluck(:value)).to eq(['foo']) + context "when custom fields are not conflicting" do + it "merges" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + result = MergeSupporters.selected({name: "Penelope Schultz"}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, true) + expect(result[:json].custom_field_joins.pluck(:value)).to eq(["foo"]) end end end - context 'when false' do - context 'when custom fields are conflicting' do + context "when false" do + context "when custom fields are conflicting" do # This is undesired, but it's the current behavior. # We should probably create copies of the conflicting custom fields instead. - it 'merges anyway' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'bar') - resulting_supporter = MergeSupporters.selected({name: 'Penelope Schultz'}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, false)[:json] - expect(resulting_supporter.custom_field_joins.pluck(:value)).to eq(['bar']) + it "merges anyway" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "bar") + resulting_supporter = MergeSupporters.selected({name: "Penelope Schultz"}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, false)[:json] + expect(resulting_supporter.custom_field_joins.pluck(:value)).to eq(["bar"]) end end - context 'when custom fields are not conflicting' do - it 'merges' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - result = MergeSupporters.selected({name: 'Penelope Schultz'}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, false) - expect(result[:json].custom_field_joins.pluck(:value)).to eq(['foo']) + context "when custom fields are not conflicting" do + it "merges" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + result = MergeSupporters.selected({name: "Penelope Schultz"}.with_indifferent_access, [old_supporter1.id, old_supporter2.id], np.id, nil, false) + expect(result[:json].custom_field_joins.pluck(:value)).to eq(["foo"]) end end end end end - describe '.conflicting_custom_fields?' do - context 'when some custom fields are conflicting' do - it 'returns true' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'bar') - old_supporter3.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'bar') + describe ".conflicting_custom_fields?" do + context "when some custom fields are conflicting" do + it "returns true" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "bar") + old_supporter3.custom_field_joins.create!(custom_field_master: custom_field_master, value: "bar") expect(MergeSupporters.conflicting_custom_fields?([old_supporter1, old_supporter2, old_supporter3])).to be_truthy end end - context 'when no custom fields are conflicting' do - it 'returns false' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - old_supporter3.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') + context "when no custom fields are conflicting" do + it "returns false" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + old_supporter1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + old_supporter3.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") expect(MergeSupporters.conflicting_custom_fields?([old_supporter1, old_supporter2, old_supporter3])).to be_falsy end end end - describe '.merge_by_id_groups' do - let(:supporter_1) { np.supporters.create!(name: 'Penelope Schultz') } - let(:supporter_2) { np.supporters.create!(name: 'Cacau Borges') } + describe ".merge_by_id_groups" do + let(:supporter_1) { np.supporters.create!(name: "Penelope Schultz") } + let(:supporter_2) { np.supporters.create!(name: "Cacau Borges") } let(:result) { MergeSupporters.merge_by_id_groups(np.id, [[supporter_1.id, supporter_2.id]], nil) } - it 'merges the supporters from the id groups' do + it "merges the supporters from the id groups" do expect(result).to eq([]) expect(supporter_1.reload.deleted).to be_truthy expect(supporter_2.reload.deleted).to be_truthy @@ -272,17 +269,17 @@ expect(supporter_1.reload.merged_into).to eq(supporter_2.merged_into) end - it 'creates a supporter.created object event' do - expect { result }.to change{ ObjectEvent.where(event_type: 'supporter.created').count }.by 1 + it "creates a supporter.created object event" do + expect { result }.to change { ObjectEvent.where(event_type: "supporter.created").count }.by 1 end - context 'when the supporters have custom fields' do - context 'when custom fields are conflicting' do - context 'when the skip_conflicting_custom_fields flag is true' do - it 'returns the supporters that could not be merged' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - supporter_1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - supporter_2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'bar') + context "when the supporters have custom fields" do + context "when custom fields are conflicting" do + context "when the skip_conflicting_custom_fields flag is true" do + it "returns the supporters that could not be merged" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + supporter_1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + supporter_2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "bar") result = MergeSupporters.merge_by_id_groups(np.id, [[supporter_1.id, supporter_2.id]], nil, true) expect(result).to match_array([[supporter_1.id, supporter_2.id]]) @@ -293,11 +290,11 @@ end end - context 'when the skip_conflicting_custom_fields flag is false' do - it 'merges and resturns an empty array' do - custom_field_master = np.custom_field_masters.create!(name: 'A Custom Field') - supporter_1.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'foo') - supporter_2.custom_field_joins.create!(custom_field_master: custom_field_master, value: 'bar') + context "when the skip_conflicting_custom_fields flag is false" do + it "merges and resturns an empty array" do + custom_field_master = np.custom_field_masters.create!(name: "A Custom Field") + supporter_1.custom_field_joins.create!(custom_field_master: custom_field_master, value: "foo") + supporter_2.custom_field_joins.create!(custom_field_master: custom_field_master, value: "bar") expect(result).to eq([]) expect(supporter_1.reload.deleted).to be_truthy diff --git a/spec/lib/multiple_condition_search_spec.rb b/spec/lib/multiple_condition_search_spec.rb index 208aa9af7..07f239e92 100644 --- a/spec/lib/multiple_condition_search_spec.rb +++ b/spec/lib/multiple_condition_search_spec.rb @@ -3,15 +3,13 @@ describe MultipleConditionSearch do describe ".find" do - let!(:parent) { create(:simple_object)} - let!(:child_obj_1) { create(:simple_object, parent: parent)} - let!(:child_obj_2) { create(:simple_object, parent: parent)} - context 'on the first condition' do - - - context 'no record is found' do - let(:search_obj) { MultipleConditionSearch.new([{houid:'some fake houid'}])} - let!(:result) {search_obj.find(SimpleObject.all)} + let!(:parent) { create(:simple_object) } + let!(:child_obj_1) { create(:simple_object, parent: parent) } + let!(:child_obj_2) { create(:simple_object, parent: parent) } + context "on the first condition" do + context "no record is found" do + let(:search_obj) { MultipleConditionSearch.new([{houid: "some fake houid"}]) } + let!(:result) { search_obj.find(SimpleObject.all) } it "will return nil" do expect(result).to be_nil @@ -26,9 +24,9 @@ end end - context 'the correct record is found' do - let(:search_obj) { MultipleConditionSearch.new([{houid: parent.houid}])} - let!(:result) {search_obj.find(SimpleObject.all)} + context "the correct record is found" do + let(:search_obj) { MultipleConditionSearch.new([{houid: parent.houid}]) } + let!(:result) { search_obj.find(SimpleObject.all) } it "will return parent" do expect(result).to eq parent @@ -43,10 +41,9 @@ end end - context 'multiple records are found' do - - let(:search_obj) { MultipleConditionSearch.new([["parent_id = ?", parent.id]])} - let!(:result) {search_obj.find(SimpleObject.all)} + context "multiple records are found" do + let(:search_obj) { MultipleConditionSearch.new([["parent_id = ?", parent.id]]) } + let!(:result) { search_obj.find(SimpleObject.all) } it "will return nil" do expect(result).to eq nil @@ -59,18 +56,18 @@ it "will have an error of multiple_values" do expect(search_obj.error).to eq :multiple_values end - end - end - context 'on multiple conditions' do - context 'no record is found' do - let(:search_obj) { MultipleConditionSearch.new([ - ["houid = ?", 'some fake houid'], - ["houid = ? or houid = 'another fake houid'", 'some_fake_houid'] - ])} - let!(:result) {search_obj.find(SimpleObject.all)} + context "on multiple conditions" do + context "no record is found" do + let(:search_obj) { + MultipleConditionSearch.new([ + ["houid = ?", "some fake houid"], + ["houid = ? or houid = 'another fake houid'", "some_fake_houid"] + ]) + } + let!(:result) { search_obj.find(SimpleObject.all) } it "will return nil" do expect(result).to be_nil @@ -85,12 +82,14 @@ end end - context 'the correct record is found' do - let(:search_obj) { MultipleConditionSearch.new([ - {parent_id: parent.id}, - ['parent_id = ? AND houid = ?', parent.id, child_obj_2.houid] - ])} - let!(:result) {search_obj.find(SimpleObject.all)} + context "the correct record is found" do + let(:search_obj) { + MultipleConditionSearch.new([ + {parent_id: parent.id}, + ["parent_id = ? AND houid = ?", parent.id, child_obj_2.houid] + ]) + } + let!(:result) { search_obj.find(SimpleObject.all) } it "will return child_obj_2" do expect(result).to eq child_obj_2 @@ -105,12 +104,14 @@ end end - context 'multiple records are found' do - let(:search_obj) { MultipleConditionSearch.new([ - "parent_id = #{parent.id}", - ["parent_id = ? AND (houid = ? OR houid = ?)", parent.id, child_obj_1.houid, child_obj_2.houid] - ])} - let!(:result) {search_obj.find(SimpleObject.all)} + context "multiple records are found" do + let(:search_obj) { + MultipleConditionSearch.new([ + "parent_id = #{parent.id}", + ["parent_id = ? AND (houid = ? OR houid = ?)", parent.id, child_obj_1.houid, child_obj_2.houid] + ]) + } + let!(:result) { search_obj.find(SimpleObject.all) } it "will return nil" do expect(result).to be_nil @@ -124,22 +125,19 @@ expect(search_obj.error).to eq :multiple_values end end - end - context 'does not crash with quotes' do - let(:search_obj) { + context "does not crash with quotes" do + let(:search_obj) { fake_houid = "O'Leary" MultipleConditionSearch.new([ houid: fake_houid ]) } - - it 'doesnt raise an error' do - expect {search_obj.find(SimpleObject.all)}.to_not raise_error + it "doesnt raise an error" do + expect { search_obj.find(SimpleObject.all) }.to_not raise_error end - end end -end \ No newline at end of file +end diff --git a/spec/lib/name_copy_naming_algorithm_spec.rb b/spec/lib/name_copy_naming_algorithm_spec.rb index b506d8b63..dd12d7366 100644 --- a/spec/lib/name_copy_naming_algorithm_spec.rb +++ b/spec/lib/name_copy_naming_algorithm_spec.rb @@ -1,49 +1,48 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe NameCopyNamingAlgorithm do - describe '.create_copy_name' do + describe ".create_copy_name" do before(:all) { - Timecop.freeze(2020,5,4) + Timecop.freeze(2020, 5, 4) } after(:all) { - Timecop.return + Timecop.return } def set_name(name) @name = name end - let(:short_name) { "short name"} - let(:short_name_copy_today) { "short name (2020-05-04 copy) 00"} - let(:short_name_copy_today_plus_1) { "short name (2020-05-04 copy) 01"} - let(:short_name_copy_yesterday) { "short name (2020-05-03 copy) 00"} - let(:short_name_copy_today_base) { "short name (2020-05-04 copy)"} - - let(:long_name) {"campaign_name is so long that it must be shortened down" } - let(:long_name_copy_today) {"#{long_name_copy_today_base} 00"} - let(:long_name_copy_today_plus_1) {"#{long_name_copy_today_base} 01"} - let(:long_name_copy_yesterday) {"campaign_name is so long that it must b (2020-05-03 copy) 00"} - let(:long_name_copy_today_base) {"campaign_name is so long that it must b (2020-05-04 copy)"} - let(:nonprofit) {force_create(:nonprofit)} - - - describe 'events' do - - let(:event) {force_create(:event, :name => @name, nonprofit: nonprofit)} - let(:event2) {force_create(:event, :name => @name2, nonprofit:nonprofit)} - let(:events_at_max_copies) { (0..30).collect{|i| - force_create(:event, name: "#{@copy_base} #{"%02d" % i}", nonprofit:nonprofit) - }} - let(:algo) {NameCopyNamingAlgorithm.new(Event, nonprofit.id)} - describe 'short event names' do - - it 'not a copy' do + let(:short_name) { "short name" } + let(:short_name_copy_today) { "short name (2020-05-04 copy) 00" } + let(:short_name_copy_today_plus_1) { "short name (2020-05-04 copy) 01" } + let(:short_name_copy_yesterday) { "short name (2020-05-03 copy) 00" } + let(:short_name_copy_today_base) { "short name (2020-05-04 copy)" } + + let(:long_name) { "campaign_name is so long that it must be shortened down" } + let(:long_name_copy_today) { "#{long_name_copy_today_base} 00" } + let(:long_name_copy_today_plus_1) { "#{long_name_copy_today_base} 01" } + let(:long_name_copy_yesterday) { "campaign_name is so long that it must b (2020-05-03 copy) 00" } + let(:long_name_copy_today_base) { "campaign_name is so long that it must b (2020-05-04 copy)" } + let(:nonprofit) { force_create(:nonprofit) } + + describe "events" do + let(:event) { force_create(:event, name: @name, nonprofit: nonprofit) } + let(:event2) { force_create(:event, name: @name2, nonprofit: nonprofit) } + let(:events_at_max_copies) { + (0..30).collect { |i| + force_create(:event, name: "#{@copy_base} #{"%02d" % i}", nonprofit: nonprofit) + } + } + let(:algo) { NameCopyNamingAlgorithm.new(Event, nonprofit.id) } + describe "short event names" do + it "not a copy" do @name = short_name event expect(algo.create_copy_name(@name)).to eq short_name_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = short_name @name2 = short_name_copy_today event @@ -52,7 +51,7 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_name_copy_today_plus_1 end - it 'one copy yesterday exists' do + it "one copy yesterday exists" do @name = short_name_copy_yesterday @name2 = short_name event @@ -61,20 +60,18 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_name_copy_today end - it 'has 30 as max copies' do + it "has 30 as max copies" do expect(algo.max_copies).to eq 30 end - end - describe 'long event names' do - - it 'not a copy' do + describe "long event names" do + it "not a copy" do @name = long_name event expect(algo.create_copy_name(@name)).to eq long_name_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = long_name @name2 = long_name_copy_today event @@ -83,7 +80,7 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq long_name_copy_today_plus_1 end - it 'one copy yesterday exists' do + it "one copy yesterday exists" do @name = long_name_copy_yesterday @name2 = long_name event @@ -92,26 +89,23 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq long_name_copy_today end - - it 'has 30 as max copies' do + it "has 30 as max copies" do expect(algo.max_copies).to eq 30 end - end end - describe 'campaigns' do - let(:campaign) {force_create(:campaign, :name => @name, nonprofit: nonprofit)} - let(:campaign2) {force_create(:campaign, :name => @name2, nonprofit:nonprofit)} - let(:algo) {NameCopyNamingAlgorithm.new(Campaign, nonprofit.id)} - describe 'short campaign names' do - - it 'not a copy' do + describe "campaigns" do + let(:campaign) { force_create(:campaign, name: @name, nonprofit: nonprofit) } + let(:campaign2) { force_create(:campaign, name: @name2, nonprofit: nonprofit) } + let(:algo) { NameCopyNamingAlgorithm.new(Campaign, nonprofit.id) } + describe "short campaign names" do + it "not a copy" do @name = short_name campaign expect(algo.create_copy_name(@name)).to eq short_name_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = short_name @name2 = short_name_copy_today campaign @@ -120,7 +114,7 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_name_copy_today_plus_1 end - it 'one copy yesterday exists' do + it "one copy yesterday exists" do @name = short_name_copy_yesterday @name2 = short_name campaign @@ -128,18 +122,15 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_name_copy_today end - - end - describe 'long campaign names' do - - it 'not a copy' do + describe "long campaign names" do + it "not a copy" do @name = long_name campaign expect(algo.create_copy_name(@name)).to eq long_name_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = long_name @name2 = long_name_copy_today campaign @@ -148,7 +139,7 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq long_name_copy_today_plus_1 end - it 'one copy yesterday exists' do + it "one copy yesterday exists" do @name = long_name_copy_yesterday @name2 = long_name campaign @@ -160,4 +151,3 @@ def set_name(name) end end end - diff --git a/spec/lib/numeric_spec.rb b/spec/lib/numeric_spec.rb index 74e69bd32..286d50295 100644 --- a/spec/lib/numeric_spec.rb +++ b/spec/lib/numeric_spec.rb @@ -1,99 +1,94 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'numeric' +require "numeric" describe Numeric do - - describe '#floor_for_delta' do - it 'rejects non integers' do - expect { 2.floor_for_delta("test")}.to raise_error(ArgumentError) - expect { 2.floor_for_delta(2.3)}.to raise_error(ArgumentError) - end - - it 'rejects negative integers' do - expect { 2.floor_for_delta(-1)}.to raise_error(ArgumentError) - end - - it 'handles on -25' do - expect(-25.floor_for_delta(25)).to eq -25 + describe "#floor_for_delta" do + it "rejects non integers" do + expect { 2.floor_for_delta("test") }.to raise_error(ArgumentError) + expect { 2.floor_for_delta(2.3) }.to raise_error(ArgumentError) end - it 'handles on -24.5' do - expect(-24.5.floor_for_delta(25)).to eq -25 - end + it "rejects negative integers" do + expect { 2.floor_for_delta(-1) }.to raise_error(ArgumentError) + end - it 'handles on -1' do - expect(-1.floor_for_delta(25)).to eq -25 + it "handles on -25" do + expect(-25.floor_for_delta(25)).to eq(-25) end + it "handles on -24.5" do + expect(-24.5.floor_for_delta(25)).to eq(-25) + end + it "handles on -1" do + expect(-1.floor_for_delta(25)).to eq(-25) + end - it 'handles on 0' do - expect(0.floor_for_delta(25)).to eq 0 + it "handles on 0" do + expect(0.floor_for_delta(25)).to eq 0 end - it 'handles on .5' do - expect(0.5.floor_for_delta(25)).to eq 0 - end + it "handles on .5" do + expect(0.5.floor_for_delta(25)).to eq 0 + end - it 'handles on 1' do - expect(1.floor_for_delta(25)).to eq 0 + it "handles on 1" do + expect(1.floor_for_delta(25)).to eq 0 end - it 'handles on 25' do - expect(25.floor_for_delta(25)).to eq 25 + it "handles on 25" do + expect(25.floor_for_delta(25)).to eq 25 end - it 'handles on 25.5' do - expect(25.5.floor_for_delta(25)).to eq 25 - end + it "handles on 25.5" do + expect(25.5.floor_for_delta(25)).to eq 25 + end end - describe '#ceil_for_delta' do - it 'rejects non integers' do - expect { 2.ceil_for_delta("test")}.to raise_error(ArgumentError) - expect { 2.ceil_for_delta(2.3)}.to raise_error(ArgumentError) + describe "#ceil_for_delta" do + it "rejects non integers" do + expect { 2.ceil_for_delta("test") }.to raise_error(ArgumentError) + expect { 2.ceil_for_delta(2.3) }.to raise_error(ArgumentError) end - it 'rejects negative integers' do - expect { 2.ceil_for_delta(-1)}.to raise_error(ArgumentError) + it "rejects negative integers" do + expect { 2.ceil_for_delta(-1) }.to raise_error(ArgumentError) end - it 'handles on -25.5' do - expect(-25.5.ceil_for_delta(25)).to eq -25 - end - - it 'handles on -25' do - expect(-25.ceil_for_delta(25)).to eq -25 - end + it "handles on -25.5" do + expect(-25.5.ceil_for_delta(25)).to eq(-25) + end + it "handles on -25" do + expect(-25.ceil_for_delta(25)).to eq(-25) + end - it 'handles on -24.5' do - expect(-24.5.ceil_for_delta(25)).to eq 0 - end + it "handles on -24.5" do + expect(-24.5.ceil_for_delta(25)).to eq 0 + end - it 'handles on -1' do - expect(-1.ceil_for_delta(25)).to eq 0 - end + it "handles on -1" do + expect(-1.ceil_for_delta(25)).to eq 0 + end - it 'handles on 0' do - expect(0.ceil_for_delta(25)).to eq 0 + it "handles on 0" do + expect(0.ceil_for_delta(25)).to eq 0 end - it 'handles on .5' do - expect(0.5.ceil_for_delta(25)).to eq 25 - end + it "handles on .5" do + expect(0.5.ceil_for_delta(25)).to eq 25 + end - it 'handles on 1' do - expect(1.ceil_for_delta(25)).to eq 25 - end + it "handles on 1" do + expect(1.ceil_for_delta(25)).to eq 25 + end - it 'handles on 25' do - expect(25.ceil_for_delta(25)).to eq 25 + it "handles on 25" do + expect(25.ceil_for_delta(25)).to eq 25 end - it 'handles on 25.5' do - expect(25.ceil_for_delta(25)).to eq 25 - end + it "handles on 25.5" do + expect(25.ceil_for_delta(25)).to eq 25 + end end - end diff --git a/spec/lib/pay_recurring_donation_spec.rb b/spec/lib/pay_recurring_donation_spec.rb index 047e0629c..9a569b91b 100644 --- a/spec/lib/pay_recurring_donation_spec.rb +++ b/spec/lib/pay_recurring_donation_spec.rb @@ -1,63 +1,63 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - -describe PayRecurringDonation do +require "rails_helper" +describe PayRecurringDonation do before(:all) do - #@data = PsqlFixtures.init - # @result = @data['recurring_donation'] + # @data = PsqlFixtures.init + # @result = @data['recurring_donation'] end before(:each) do ActiveJob::Base.queue_adapter = :test end - - describe '.with_stripe' do + describe ".with_stripe" do include_context :shared_donation_charge_context - - around (:each) do |example| - Timecop.freeze( 2020, 5,4) do - StripeMockHelper.mock do + + around(:each) do |example| + Timecop.freeze(2020, 5, 4) do + StripeMockHelper.mock do example.run end end end - let(:nonprofit) { force_create(:nonprofit, statement:'swhtowht', name: 'atata')} - let(:supporter) {force_create(:supporter, nonprofit:nonprofit)} + let(:nonprofit) { force_create(:nonprofit, statement: "swhtowht", name: "atata") } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } - let(:stripe_cust_id) { customer = Stripe::Customer.create(); - customer.id} + let(:stripe_cust_id) { + customer = Stripe::Customer.create + customer.id + } let(:card) { - card = Stripe::Customer.create_source(stripe_cust_id, {source: StripeMockHelper.generate_card_token(brand: 'Visa', country: 'US')}) + card = Stripe::Customer.create_source(stripe_cust_id, {source: StripeMockHelper.generate_card_token(brand: "Visa", country: "US")}) force_create(:card, holder: supporter, stripe_customer_id: stripe_cust_id, stripe_card_id: card.id) } - let(:donation) {force_create(:donation, supporter: supporter, amount: 300, card: card, nonprofit: nonprofit)} - let(:recurring_donation) { force_create(:recurring_donation, donation: donation, start_date: Time.now - 1.day, active:true, nonprofit: nonprofit, n_failures: 0, interval: 1, time_unit: 'month')} + let(:donation) { force_create(:donation, supporter: supporter, amount: 300, card: card, nonprofit: nonprofit) } + let(:recurring_donation) { force_create(:recurring_donation, donation: donation, start_date: Time.now - 1.day, active: true, nonprofit: nonprofit, n_failures: 0, interval: 1, time_unit: "month") } let(:misc_recurring_donation_info__covered) { force_create(:misc_recurring_donation_info, recurring_donation: recurring_donation, fee_covered: true) } - let(:recent_charge) {force_create(:charge, donation:donation, card:card, amount: 300, status:'paid', created_at: Time.now - 1.day)} + let(:recent_charge) { force_create(:charge, donation: donation, card: card, amount: 300, status: "paid", created_at: Time.now - 1.day) } - let(:successful_charge_argument) { + let(:successful_charge_argument) { { - customer:stripe_cust_id, - amount:300, - currency:'usd', - statement_descriptor_suffix:'Donation swhtowht', + customer: stripe_cust_id, + amount: 300, + currency: "usd", + statement_descriptor_suffix: "Donation swhtowht", metadata: { - kind: 'RecurringDonation', + kind: "RecurringDonation", nonprofit_id: nonprofit.id }, - application_fee:37 + application_fee: 37 } } let(:covered_result) { misc_recurring_donation_info__covered - PayRecurringDonation.with_stripe(recurring_donation.id) + PayRecurringDonation.with_stripe(recurring_donation.id) } let(:uncovered_result) { @@ -78,41 +78,42 @@ create(:user, id: 540) end - context 'result when fees covered' do + context "result when fees covered" do it { - expect(covered_result).to_not eq false + expect(covered_result).to_not eq false } it { - expect {covered_result}.to have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) - .with(donation:donation, legacy_payment: an_instance_of(Payment).and( + expect { covered_result }.to have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) + .with(donation: donation, legacy_payment: an_instance_of(Payment).and( have_attributes( gross_amount: 300, supporter: supporter, donation: donation - ))) + ) + )) } it { covered_result expect(donation.payments.first.misc_payment_info.fee_covered).to eq true } - end - context 'result when fees not covered' do + context "result when fees not covered" do it { - expect(uncovered_result).to_not eq false + expect(uncovered_result).to_not eq false } it { - expect {uncovered_result}.to have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) - .with(donation:donation, legacy_payment: an_instance_of(Payment).and( + expect { uncovered_result }.to have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) + .with(donation: donation, legacy_payment: an_instance_of(Payment).and( have_attributes( gross_amount: 300, supporter: supporter, donation: donation - ))) + ) + )) } it { @@ -121,45 +122,41 @@ } end - context 'result when not due' do - + context "result when not due" do it { expect(result_with_recent_charge).to eq false } it { - expect {result_with_recent_charge}.to_not have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) + expect { result_with_recent_charge }.to_not have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) } - end - context 'result when not due but forced' do + context "result when not due but forced" do it { - expect( result_with_recent_charge_but_forced ).to_not eq false + expect(result_with_recent_charge_but_forced).to_not eq false } it { - expect {result_with_recent_charge_but_forced}.to have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) - .with(donation:donation, legacy_payment: an_instance_of(Payment).and( + expect { result_with_recent_charge_but_forced }.to have_enqueued_job(InlineJob::ModernObjectDonationStripeChargeJob) + .with(donation: donation, legacy_payment: an_instance_of(Payment).and( have_attributes( gross_amount: 300, supporter: supporter, donation: donation - ))) + ) + )) } end - - context 'n_failures = 0 and failed again' do - + context "n_failures = 0 and failed again" do before(:each) do recurring_donation.n_failures = 0 recurring_donation.save! StripeMockHelper.prepare_card_error(:card_declined) end - it 'sets n_failures to 1' do - + it "sets n_failures to 1" do PayRecurringDonation.with_stripe(recurring_donation.id, true) recurring_donation.reload @@ -167,10 +164,10 @@ expect(recurring_donation.n_failures).to eq 1 end - it 'sends an email to the donor but not nonprofit' do + it "sends an email to the donor but not nonprofit" do delayed_mailer = double(DonationMailer) expect(DonationMailer).to receive(:delay).once.and_return(delayed_mailer) - + expect(delayed_mailer).to receive(:donor_failed_recurring_donation).with(recurring_donation.donation_id) expect(delayed_mailer).to_not receive(:nonprofit_failed_recurring_donation) @@ -179,16 +176,14 @@ end end - context 'n_failures = 2 and failed again' do - + context "n_failures = 2 and failed again" do before(:each) do recurring_donation.n_failures = 2 recurring_donation.save! StripeMockHelper.prepare_card_error(:card_declined) end - it 'sets n_failures to 3' do - + it "sets n_failures to 3" do PayRecurringDonation.with_stripe(recurring_donation.id, true) recurring_donation.reload @@ -196,10 +191,10 @@ expect(recurring_donation.n_failures).to eq 3 end - it 'sends an email to the nonprofit' do + it "sends an email to the nonprofit" do delayed_mailer = double(DonationMailer) allow(DonationMailer).to receive(:delay).and_return(delayed_mailer) - + expect(delayed_mailer).to receive(:donor_failed_recurring_donation).with(recurring_donation.donation_id) expect(delayed_mailer).to receive(:nonprofit_failed_recurring_donation).with(recurring_donation.donation_id) @@ -207,10 +202,9 @@ PayRecurringDonation.with_stripe(recurring_donation.id, true) end end - end - - describe '.pay_all_due_with_stripe', :pending => true do + end + describe ".pay_all_due_with_stripe", pending: true do # it 'queues a job to pay each due recurring donation' do # Timecop.freeze(Time.parse("2020-02-01").utc) do # VCR.use_cassette('PayRecurringDonation/pay_all_due_with_stripe') do @@ -225,6 +219,4 @@ # Psql.execute("DELETE FROM delayed_jobs WHERE queue='rec-don-payments'") # end end - - end diff --git a/spec/lib/payment_dupes_spec.rb b/spec/lib/payment_dupes_spec.rb index 8277a54be..6f214c46a 100644 --- a/spec/lib/payment_dupes_spec.rb +++ b/spec/lib/payment_dupes_spec.rb @@ -1,751 +1,751 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe PaymentDupes, skip: true do # this was a one-off - let(:nonprofit) { create(:fv_poverty, timezone: 'America/Chicago', vetted: true) } - let(:supporter) { create(:supporter, nonprofit: nonprofit) } - let!(:etap_import) { create(:e_tap_import, nonprofit: nonprofit) } - - describe '#can_copy_dedication?' do - context 'when the source donation has an empty dedication' do - it 'returns true' do - source_donation = nonprofit.donations.create(dedication: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - target_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - expect(described_class.can_copy_dedication?(source_payment, target_payment)).to be_truthy - end + let(:nonprofit) { create(:fv_poverty, timezone: "America/Chicago", vetted: true) } + let(:supporter) { create(:supporter, nonprofit: nonprofit) } + let!(:etap_import) { create(:e_tap_import, nonprofit: nonprofit) } + + describe "#can_copy_dedication?" do + context "when the source donation has an empty dedication" do + it "returns true" do + source_donation = nonprofit.donations.create(dedication: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + target_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + expect(described_class.can_copy_dedication?(source_payment, target_payment)).to be_truthy + end + end + + context "when the target donation has a dedication" do + context "and the dedication is the same for both target and source donations" do + it "returns true" do + target_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_dedication?(source_payment, target_payment)).to be_truthy end + end - context 'when the target donation has a dedication' do - context 'and the dedication is the same for both target and source donations' do - it 'returns true' do - target_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_dedication?(source_payment, target_payment)).to be_truthy - end - end - - context 'and the dedication is different for both target and source donations' do - it 'returns false' do - target_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(dedication: 'Some other dedication', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_dedication?(source_payment, target_payment)).to be_falsy - end - end + context "and the dedication is different for both target and source donations" do + it "returns false" do + target_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(dedication: "Some other dedication", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_dedication?(source_payment, target_payment)).to be_falsy end + end + end + end + + describe "#can_copy_designation?" do + context "when the source donation has an empty dedication" do + it "returns true" do + source_donation = nonprofit.donations.create(designation: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + target_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + expect(described_class.can_copy_designation?(source_payment, target_payment, ["A designation that should become a comment"])).to be_truthy + end end - describe '#can_copy_designation?' do - context 'when the source donation has an empty dedication' do - it 'returns true' do - source_donation = nonprofit.donations.create(designation: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - target_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - expect(described_class.can_copy_designation?(source_payment, target_payment, ['A designation that should become a comment'])).to be_truthy - end + context "when the target donation has a designation" do + context "and the designation is the same for both target and source donations" do + it "returns true" do + target_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_designation?(source_payment, target_payment, ["A designation that should become a comment"])).to be_truthy end + end + + context "and the designation is different for both target and source donations" do + it "returns false" do + target_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(designation: "Some other designation", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_designation?(source_payment, target_payment, ["A designation that should become a comment"])).to be_falsy + end + + context "and the designation is one that should become a comment" do + it "returns true" do + target_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! - context 'when the target donation has a designation' do - context 'and the designation is the same for both target and source donations' do - it 'returns true' do - target_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_designation?(source_payment, target_payment, ['A designation that should become a comment'])).to be_truthy - end - end - - context 'and the designation is different for both target and source donations' do - it 'returns false' do - target_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(designation: 'Some other designation', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_designation?(source_payment, target_payment, ['A designation that should become a comment'])).to be_falsy - end - - context 'and the designation is one that should become a comment' do - it 'returns true' do - target_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(designation: 'A designation that should become a comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_designation?(source_payment, target_payment, ['A designation that should become a comment'])).to be_truthy - end - end - end + source_donation = nonprofit.donations.create(designation: "A designation that should become a comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_designation?(source_payment, target_payment, ["A designation that should become a comment"])).to be_truthy + end end + end + end + end + + describe "#can_copy_comment?" do + context "when the source donation has an empty comment" do + it "returns true" do + source_donation = nonprofit.donations.create(comment: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + expect(described_class.can_copy_comment?(source_payment, target_payment, ["A designation to become a comment"])).to be_truthy + end end - describe '#can_copy_comment?' do - context 'when the source donation has an empty comment' do - it 'returns true' do - source_donation = nonprofit.donations.create(comment: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - expect(described_class.can_copy_comment?(source_payment, target_payment, ['A designation to become a comment'])).to be_truthy - end + context "when the target donation has a comment" do + context "and the comment is the same for both target and source donations" do + it "returns true" do + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_comment?(source_payment, target_payment, ["A designation to become a comment"])).to be_truthy end + end + + context "and the comment is different for both target and source donations" do + context "because a designation was copied to the comment" do + it "returns true if the only difference is the designation that was added to the comment" do + target_donation = nonprofit.donations.create(comment: "Some comment \nDesignation: A designation to become a comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_comment?(source_payment, target_payment, ["A designation to become a comment"])).to be_truthy + end + + it "returns false if its not the only difference" do + target_donation = nonprofit.donations.create(comment: "Some other comment \nDesignation: A designation to become a comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! + + expect(described_class.can_copy_comment?(source_payment, target_payment, ["A designation to become a comment"])).to be_falsy + end + end + + it "returns false" do + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit) + target_payment.save! + + source_donation = nonprofit.donations.create(comment: "Some other comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit) + source_payment.save! - context 'when the target donation has a comment' do - context 'and the comment is the same for both target and source donations' do - it 'returns true' do - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_comment?(source_payment, target_payment, ['A designation to become a comment'])).to be_truthy - end - end - - context 'and the comment is different for both target and source donations' do - context 'because a designation was copied to the comment' do - it 'returns true if the only difference is the designation that was added to the comment' do - target_donation = nonprofit.donations.create(comment: "Some comment \nDesignation: A designation to become a comment", amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_comment?(source_payment, target_payment, ['A designation to become a comment'])).to be_truthy - end - - it 'returns false if its not the only difference' do - target_donation = nonprofit.donations.create(comment: "Some other comment \nDesignation: A designation to become a comment", amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_comment?(source_payment, target_payment, ['A designation to become a comment'])).to be_falsy - end - end - - it 'returns false' do - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit) - target_payment.save! - - source_donation = nonprofit.donations.create(comment: 'Some other comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit) - source_payment.save! - - expect(described_class.can_copy_comment?(source_payment, target_payment, ['A designation to become a comment'])).to be_falsy - end - end + expect(described_class.can_copy_comment?(source_payment, target_payment, ["A designation to become a comment"])).to be_falsy end + end end + end - describe '#remove_payment_dupes' do - before do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '123']]) + describe "#remove_payment_dupes" do + before do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "123"]]) + end + + around(:each) do |example| + Timecop.freeze(Time.local(2022, 2, 9)) do + example.run + end + end + + context "when there is a payment and an offsite payment with the same data" do + it "deletes the offsite payment" do + source_donation = nonprofit.donations.create(comment: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + context "when the donor covered the fee" do + it "deletes the offsite payment based on the net amount" do + source_donation = nonprofit.donations.create(comment: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 95, fee_total: -5, net_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) end + end + + context "payments saved under different timezones" do + it "matches if the dates are different because of different timezones" do + source_donation = nonprofit.donations.create(comment: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.new(2021, 5, 24, 5, 0, 0), supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.new(2021, 5, 25, 1, 0, 0), kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - around(:each) do |example| - Timecop.freeze(Time.local(2022, 2, 9)) do - example.run - end + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) end + end + + it "creates a payment dupe status" do + source_donation = nonprofit.donations.create(comment: "", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.payment_dupe_status.matched_with_offline).to eq([source_payment.id]) + end + + it "copies the dedication" do + source_donation = nonprofit.donations.create(dedication: "A dedication", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(dedication: "", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.dedication).to eq("A dedication") + end + + it "copies the comment" do + source_donation = nonprofit.donations.create(comment: "A comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.comment).to eq("A comment") + end + + it "copies the designation" do + source_donation = nonprofit.donations.create(designation: "A designation", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(designation: "", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.designation).to eq("A designation") + end + + it "deletes the related activities" do + donation = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => Time.now.to_s, "amount" => 100}) + source_payment = Payment.find(donation[:json]["payment"]["id"]) + activity = Activity.where(attachment_id: source_payment.id, attachment_type: "Payment").first + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { activity.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "deletes the offsite_payment" do + donation = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => Time.now.to_s, "amount" => 100}) + source_payment = Payment.find(donation[:json]["payment"]["id"]) + offsite = source_payment.offsite_payment + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { offsite.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + context "when the designation is one that should be a comment" do + it "copies the designation as a comment" do + source_donation = nonprofit.donations.create(designation: "A designation that should become a comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(designation: "", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.comment.include?("A designation that should become a comment")).to be_truthy + end + end + + context "when the dedication is conflicting" do + it "does not delete the offline donation" do + source_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(dedication: "Some other dedication", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.not_to raise_error + end + end + + context "when the designation is conflicting" do + it "does not delete the offline donation" do + source_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(designation: "Some other designation", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.not_to raise_error + end + end + + context "when the comment is conflicting" do + it "does not delete the offline donation" do + source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(comment: "Some other comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Donation", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.not_to raise_error + end + end + + context "when the payment kind is a ticket" do + it "deletes the offsite payment" do + source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Ticket", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "creates a payment dupe status" do + source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Ticket", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.payment_dupe_status.matched_with_offline).to eq([source_payment.id]) + end + + it "deletes the related activities" do + donation = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => Time.now.to_s, "amount" => 100}) + source_payment = Payment.find(donation[:json]["payment"]["id"]) + activity = Activity.where(attachment_id: source_payment.id, attachment_type: "Payment").first + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Ticket", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { activity.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "deletes the offsite_payment" do + donation = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => Time.now.to_s, "amount" => 100}) + source_payment = Payment.find(donation[:json]["payment"]["id"]) + offsite = source_payment.offsite_payment + + target_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "Ticket", supporter: supporter, gross_amount: 100) + target_payment.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { offsite.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + context "when the payment kind is a recurring donation" do + it "deletes the offsite payment" do + source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + source_donation.save! + source_donation_2 = nonprofit.donations.create(amount: 100, supporter: supporter) + source_donation_2.save! + source_donation_3 = nonprofit.donations.create(amount: 100, supporter: supporter) + source_donation_3.save! + + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + source_payment_2 = source_donation_2.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "OffsitePayment", supporter: supporter, gross_amount: 100) + source_payment_2.save! + source_payment_3 = source_donation_3.payments.create(nonprofit: nonprofit, date: Time.now - 5.days, kind: "OffsitePayment", supporter: supporter, gross_amount: 100) + source_payment_3.save! + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment.save! + target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment_2.save! + target_payment_3 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 5.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment_3.save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_3).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { source_payment_2.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { source_payment_3.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "deletes the offsite_payment" do + donation = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => Time.now.to_s, "amount" => 100}) + source_payment = Payment.find(donation[:json]["payment"]["id"]) + offsite = source_payment.offsite_payment + + donation_2 = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => (Time.now - 2.days).to_s, "amount" => 100}) + source_payment_2 = Payment.find(donation_2[:json]["payment"]["id"]) + offsite_2 = source_payment_2.offsite_payment + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + + target_donation_2 = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation_2.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { offsite.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { offsite_2.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "deletes the activities" do + donation = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => Time.now.to_s, "amount" => 100}) + source_payment = Payment.find(donation[:json]["payment"]["id"]) + activity = Activity.where(attachment_id: source_payment.id, attachment_type: "Payment").first + + donation_2 = InsertDonation.offsite({:supporter_id => supporter.id, :nonprofit_id => nonprofit.id, "supporter_id" => supporter.id, "nonprofit_id" => nonprofit.id, "date" => (Time.now - 2.days).to_s, "amount" => 100}) + source_payment_2 = Payment.find(donation_2[:json]["payment"]["id"]) + activity_2 = Activity.where(attachment_id: source_payment_2.id, attachment_type: "Payment").first + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + + target_donation_2 = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation_2.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect { activity.reload }.to raise_error(ActiveRecord::RecordNotFound) + expect { activity_2.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it "creates a payment dupe status" do + source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "OffsitePayment", supporter: supporter, gross_amount: 200) + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment.save! + target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 200) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.payment_dupe_status.matched_with_offline).to eq([source_payment.id]) + expect(target_payment_2.reload.payment_dupe_status.matched_with_offline).to eq([source_payment_2.id]) + end + + it "copies the dedication" do + source_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "OffsitePayment", supporter: supporter, gross_amount: 200) + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment.save! + target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 200) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.dedication).to eq("Some dedication") + expect(target_payment_2.reload.donation.dedication).to eq("Some dedication") + end + + it "copies the comment" do + source_donation = nonprofit.donations.create(comment: "Some comment", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "OffsitePayment", supporter: supporter, gross_amount: 200) + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment.save! + target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 200) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.comment).to eq("Some comment") + expect(target_payment_2.reload.donation.comment).to eq("Some comment") + end + + it "copies the designation" do + source_donation = nonprofit.donations.create(designation: "Some designation", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "OffsitePayment", supporter: supporter, gross_amount: 200) + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + target_payment.save! + target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: "RecurringDonation", supporter: supporter, gross_amount: 200) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! + + described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) + expect(target_payment.reload.donation.designation).to eq("Some designation") + expect(target_payment_2.reload.donation.designation).to eq("Some designation") + end + + context "when there are multiple offline matches for the same online payment" do + it "doesnt delete the payments" do + source_donation = nonprofit.donations.create(dedication: "Some dedication", amount: 100, supporter: supporter) + source_donation.save! + source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: "OffsitePayment", date: Time.now, supporter: supporter, gross_amount: 100) + source_payment.save! + source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "OffsitePayment", supporter: supporter, gross_amount: 100) + + target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) + target_donation.save! + target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: "RecurringDonation", supporter: supporter, gross_amount: 100) + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! + + etap_import.e_tap_import_journal_entries.create(row: {"Account Number" => "123"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - context 'when there is a payment and an offsite payment with the same data' do - it 'deletes the offsite payment' do - source_donation = nonprofit.donations.create(comment: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - context 'when the donor covered the fee' do - it 'deletes the offsite payment based on the net amount' do - source_donation = nonprofit.donations.create(comment: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 95, fee_total: -5, net_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - context 'payments saved under different timezones' do - it 'matches if the dates are different because of different timezones' do - source_donation = nonprofit.donations.create(comment: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.new(2021, 5, 24, 5, 0, 0), supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.new(2021, 5, 25, 1, 0, 0), kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - it 'creates a payment dupe status' do - source_donation = nonprofit.donations.create(comment: '', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.payment_dupe_status.matched_with_offline).to eq([source_payment.id]) - end - - it 'copies the dedication' do - source_donation = nonprofit.donations.create(dedication: 'A dedication', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(dedication: '', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.dedication).to eq('A dedication') - end - - it 'copies the comment' do - source_donation = nonprofit.donations.create(comment: 'A comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: '', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.comment).to eq('A comment') - end - - it 'copies the designation' do - source_donation = nonprofit.donations.create(designation: 'A designation', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(designation: '', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.designation).to eq('A designation') - end - - it 'deletes the related activities' do - donation = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => Time.now.to_s, 'amount' => 100}) - source_payment = Payment.find(donation[:json]["payment"]["id"]) - activity = Activity.where(attachment_id: source_payment.id, attachment_type: 'Payment').first - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { activity.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'deletes the offsite_payment' do - donation = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => Time.now.to_s, 'amount' => 100}) - source_payment = Payment.find(donation[:json]["payment"]["id"]) - offsite = source_payment.offsite_payment - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { offsite.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - context 'when the designation is one that should be a comment' do - it 'copies the designation as a comment' do - source_donation = nonprofit.donations.create(designation: 'A designation that should become a comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(designation: '', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.comment.include?('A designation that should become a comment')).to be_truthy - end - end - - context 'when the dedication is conflicting' do - it 'does not delete the offline donation' do - source_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(dedication: 'Some other dedication', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.not_to raise_error - end - end - - context 'when the designation is conflicting' do - it 'does not delete the offline donation' do - source_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(designation: 'Some other designation', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.not_to raise_error - end - end - - context 'when the comment is conflicting' do - it 'does not delete the offline donation' do - source_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(comment: 'Some other comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Donation', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.not_to raise_error - end - end - - context 'when the payment kind is a ticket' do - it 'deletes the offsite payment' do - source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Ticket', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'creates a payment dupe status' do - source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Ticket', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.payment_dupe_status.matched_with_offline).to eq([source_payment.id]) - end - - it 'deletes the related activities' do - donation = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => Time.now.to_s, 'amount' => 100}) - source_payment = Payment.find(donation[:json]["payment"]["id"]) - activity = Activity.where(attachment_id: source_payment.id, attachment_type: 'Payment').first - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Ticket', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { activity.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'deletes the offsite_payment' do - donation = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => Time.now.to_s, 'amount' => 100}) - source_payment = Payment.find(donation[:json]["payment"]["id"]) - offsite = source_payment.offsite_payment - - target_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'Ticket', supporter: supporter, gross_amount: 100) - target_payment.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { offsite.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - context 'when the payment kind is a recurring donation' do - it 'deletes the offsite payment' do - source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - source_donation.save! - source_donation_2 = nonprofit.donations.create(amount: 100, supporter: supporter) - source_donation_2.save! - source_donation_3 = nonprofit.donations.create(amount: 100, supporter: supporter) - source_donation_3.save! - - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - source_payment_2 = source_donation_2.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'OffsitePayment', supporter: supporter, gross_amount: 100) - source_payment_2.save! - source_payment_3 = source_donation_3.payments.create(nonprofit: nonprofit, date: Time.now - 5.days, kind: 'OffsitePayment', supporter: supporter, gross_amount: 100) - source_payment_3.save! - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment.save! - target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment_2.save! - target_payment_3 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 5.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment_3.save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_3).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { source_payment.reload }.to raise_error(ActiveRecord::RecordNotFound) - expect { source_payment_2.reload }.to raise_error(ActiveRecord::RecordNotFound) - expect { source_payment_3.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'deletes the offsite_payment' do - donation = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => Time.now.to_s, 'amount' => 100}) - source_payment = Payment.find(donation[:json]["payment"]["id"]) - offsite = source_payment.offsite_payment - - donation_2 = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => (Time.now - 2.days).to_s, 'amount' => 100}) - source_payment_2 = Payment.find(donation_2[:json]["payment"]["id"]) - offsite_2 = source_payment_2.offsite_payment - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - - target_donation_2 = nonprofit.donations.create(amount: 100, supporter: supporter) - target_payment_2 = target_donation_2.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { offsite.reload }.to raise_error(ActiveRecord::RecordNotFound) - expect { offsite_2.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'deletes the activities' do - donation = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => Time.now.to_s, 'amount' => 100}) - source_payment = Payment.find(donation[:json]["payment"]["id"]) - activity = Activity.where(attachment_id: source_payment.id, attachment_type: 'Payment').first - - donation_2 = InsertDonation.offsite({supporter_id: supporter.id, nonprofit_id: nonprofit.id, 'supporter_id' => supporter.id, 'nonprofit_id' => nonprofit.id, 'date' => (Time.now - 2.days).to_s, 'amount' => 100}) - source_payment_2 = Payment.find(donation_2[:json]["payment"]["id"]) - activity_2 = Activity.where(attachment_id: source_payment_2.id, attachment_type: 'Payment').first - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - - target_donation_2 = nonprofit.donations.create(amount: 100, supporter: supporter) - target_payment_2 = target_donation_2.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect { activity.reload }.to raise_error(ActiveRecord::RecordNotFound) - expect { activity_2.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'creates a payment dupe status' do - source_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'OffsitePayment', supporter: supporter, gross_amount: 200) - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment.save! - target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 200) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.payment_dupe_status.matched_with_offline).to eq([source_payment.id]) - expect(target_payment_2.reload.payment_dupe_status.matched_with_offline).to eq([source_payment_2.id]) - end - - it 'copies the dedication' do - source_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'OffsitePayment', supporter: supporter, gross_amount: 200) - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment.save! - target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 200) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.dedication).to eq('Some dedication') - expect(target_payment_2.reload.donation.dedication).to eq('Some dedication') - end - - it 'copies the comment' do - source_donation = nonprofit.donations.create(comment: 'Some comment', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'OffsitePayment', supporter: supporter, gross_amount: 200) - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment.save! - target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 200) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.comment).to eq('Some comment') - expect(target_payment_2.reload.donation.comment).to eq('Some comment') - end - - it 'copies the designation' do - source_donation = nonprofit.donations.create(designation: 'Some designation', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'OffsitePayment', supporter: supporter, gross_amount: 200) - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - target_payment.save! - target_payment_2 = target_donation.payments.create(nonprofit: nonprofit, date: Time.now - 2.days, kind: 'RecurringDonation', supporter: supporter, gross_amount: 200) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) - expect(target_payment.reload.donation.designation).to eq('Some designation') - expect(target_payment_2.reload.donation.designation).to eq('Some designation') - end - - context 'when there are multiple offline matches for the same online payment' do - it 'doesnt delete the payments' do - source_donation = nonprofit.donations.create(dedication: 'Some dedication', amount: 100, supporter: supporter) - source_donation.save! - source_payment = source_donation.payments.create(nonprofit: nonprofit, kind: 'OffsitePayment', date: Time.now, supporter: supporter, gross_amount: 100) - source_payment.save! - source_payment_2 = source_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'OffsitePayment', supporter: supporter, gross_amount: 100) - - target_donation = nonprofit.donations.create(amount: 100, supporter: supporter) - target_donation.save! - target_payment = target_donation.payments.create(nonprofit: nonprofit, date: Time.now, kind: 'RecurringDonation', supporter: supporter, gross_amount: 100) - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment).save! - - etap_import.e_tap_import_journal_entries.create(row: { 'Account Number' => '123' }) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: source_payment_2).save! - - expect { described_class.remove_payment_dupes(nonprofit, ['A designation that should become a comment']) }.to change{ Payment.all.count }.by(0) - end - end - end + expect { described_class.remove_payment_dupes(nonprofit, ["A designation that should become a comment"]) }.to change { Payment.all.count }.by(0) + end end + end end + end end diff --git a/spec/lib/periodic_report_adapter/cancelled_recurring_donations_report_spec.rb b/spec/lib/periodic_report_adapter/cancelled_recurring_donations_report_spec.rb index 2425e9de8..fc6cedbe8 100644 --- a/spec/lib/periodic_report_adapter/cancelled_recurring_donations_report_spec.rb +++ b/spec/lib/periodic_report_adapter/cancelled_recurring_donations_report_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe PeriodicReportAdapter::CancelledRecurringDonationsReport do let(:nonprofit) { create(:nonprofit_base) } @@ -7,17 +7,17 @@ let(:users_list) { User.where(user_id: user) } let(:options) do { - :nonprofit_id => nonprofit.id, - :period => :last_month, - :users => users_list + nonprofit_id: nonprofit.id, + period: :last_month, + users: users_list } end let(:params) do { - :active => false, - :cancelled_at_gt_or_eq => Time.new(2021, 9, 1), - :cancelled_at_lt => Time.new(2021, 10, 1) + active: false, + cancelled_at_gt_or_eq: Time.new(2021, 9, 1), + cancelled_at_lt: Time.new(2021, 10, 1) } end @@ -38,7 +38,7 @@ .and_return(export_recurring_donations) end - it 'calls ExportRecurringDonations::initiate_export with the correct arguments' do + it "calls ExportRecurringDonations::initiate_export with the correct arguments" do subject expect(ExportRecurringDonations) .to have_received(:initiate_export) diff --git a/spec/lib/periodic_report_adapter/failed_recurring_donations_report_spec.rb b/spec/lib/periodic_report_adapter/failed_recurring_donations_report_spec.rb index c504575f0..15cb3d53e 100644 --- a/spec/lib/periodic_report_adapter/failed_recurring_donations_report_spec.rb +++ b/spec/lib/periodic_report_adapter/failed_recurring_donations_report_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe PeriodicReportAdapter::FailedRecurringDonationsReport do let(:nonprofit) { create(:nonprofit_base) } @@ -7,18 +7,18 @@ let(:users_list) { User.where(user_id: user) } let(:options) do { - :nonprofit_id => nonprofit.id, - :period => :last_month, - :users => users_list + nonprofit_id: nonprofit.id, + period: :last_month, + users: users_list } end let(:params) do { - :failed => true, - :include_last_failed_charge => true, - :from_date => Time.new(2021, 9, 1), - :before_date => Time.new(2021, 10, 1) + failed: true, + include_last_failed_charge: true, + from_date: Time.new(2021, 9, 1), + before_date: Time.new(2021, 10, 1) } end @@ -39,7 +39,7 @@ .and_return(export_recurring_donations) end - it 'calls ExportRecurringDonations::initiate_export with the correct arguments' do + it "calls ExportRecurringDonations::initiate_export with the correct arguments" do subject expect(ExportRecurringDonations) .to have_received(:initiate_export) diff --git a/spec/lib/periodic_report_adapter_spec.rb b/spec/lib/periodic_report_adapter_spec.rb index 1d937e277..ebf515930 100644 --- a/spec/lib/periodic_report_adapter_spec.rb +++ b/spec/lib/periodic_report_adapter_spec.rb @@ -1,10 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe PeriodicReportAdapter do let(:nonprofit_id) { create(:fv_poverty).id } let(:user) { create(:user) } - let(:options) { { report_type: :failed_recurring_donations, nonprofit_id: nonprofit_id, period: :last_month, users: [user] } } + let(:options) { {report_type: :failed_recurring_donations, nonprofit_id: nonprofit_id, period: :last_month, users: [user]} } let(:failed_recurring_donations_report) { double } @@ -17,7 +17,7 @@ .and_return(failed_recurring_donations_report) end - it 'returns an instance of FailedRecurringDonationsReport given a failed_recurring_donations report type and its options' do + it "returns an instance of FailedRecurringDonationsReport given a failed_recurring_donations report type and its options" do expect(subject).to eq(failed_recurring_donations_report) end end diff --git a/spec/lib/query/query_campaign_gifts_spec.rb b/spec/lib/query/query_campaign_gifts_spec.rb index e2739d492..25cdba37c 100644 --- a/spec/lib/query/query_campaign_gifts_spec.rb +++ b/spec/lib/query/query_campaign_gifts_spec.rb @@ -1,27 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QueryCampaignGifts do GIFT_LEVEL_ONE_TIME = 1111 GIFT_LEVEL_RECURRING = 5585 GIFT_LEVEL_CHANGED_RECURRING = 5512 CAMPAIGN_GIFT_OPTION_NAME = "theowthoinv" - let(:np) { force_create(:nonprofit)} - let(:supporter1) { force_create(:supporter, nonprofit: np)} - let(:supporter2) { force_create(:supporter, nonprofit: np)} - let(:campaign) { force_create(:campaign, nonprofit: np, slug: "slug stuff")} - let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, name: CAMPAIGN_GIFT_OPTION_NAME, amount_one_time: GIFT_LEVEL_ONE_TIME, amount_recurring: GIFT_LEVEL_RECURRING)} - let(:campaign_gift1) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation1)} - let(:donation1) { force_create(:donation, amount: GIFT_LEVEL_ONE_TIME, campaign: campaign, supporter:supporter1)} - - let(:payment1) {force_create(:payment, gross_amount: GIFT_LEVEL_ONE_TIME, donation: donation1)} - - let(:donation2) {force_create(:donation, amount: GIFT_LEVEL_CHANGED_RECURRING, campaign: campaign, supporter:supporter2)} - let(:payment2) {force_create(:payment, gross_amount: GIFT_LEVEL_RECURRING, donation: donation2)} - let(:payment3) {force_create(:payment, gross_amount: GIFT_LEVEL_CHANGED_RECURRING, donation: donation2)} - let(:campaign_gift2) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation2)} - let(:recurring) {force_create(:recurring_donation, donation: donation2, amount: GIFT_LEVEL_CHANGED_RECURRING)} - + let(:np) { force_create(:nonprofit) } + let(:supporter1) { force_create(:supporter, nonprofit: np) } + let(:supporter2) { force_create(:supporter, nonprofit: np) } + let(:campaign) { force_create(:campaign, nonprofit: np, slug: "slug stuff") } + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, name: CAMPAIGN_GIFT_OPTION_NAME, amount_one_time: GIFT_LEVEL_ONE_TIME, amount_recurring: GIFT_LEVEL_RECURRING) } + let(:campaign_gift1) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation1) } + let(:donation1) { force_create(:donation, amount: GIFT_LEVEL_ONE_TIME, campaign: campaign, supporter: supporter1) } + + let(:payment1) { force_create(:payment, gross_amount: GIFT_LEVEL_ONE_TIME, donation: donation1) } + + let(:donation2) { force_create(:donation, amount: GIFT_LEVEL_CHANGED_RECURRING, campaign: campaign, supporter: supporter2) } + let(:payment2) { force_create(:payment, gross_amount: GIFT_LEVEL_RECURRING, donation: donation2) } + let(:payment3) { force_create(:payment, gross_amount: GIFT_LEVEL_CHANGED_RECURRING, donation: donation2) } + let(:campaign_gift2) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation2) } + let(:recurring) { force_create(:recurring_donation, donation: donation2, amount: GIFT_LEVEL_CHANGED_RECURRING) } let(:init_all) { np @@ -36,7 +35,6 @@ gift_level_match } let(:gift_level_match) { - QueryCampaignGifts.report_metrics(campaign.id) } @@ -44,18 +42,18 @@ init_all } - it 'counts gift donations properly' do + it "counts gift donations properly" do glm = gift_level_match data = glm[:data] expect(data).to eq([ - { - "name" => CAMPAIGN_GIFT_OPTION_NAME, - 'total_donations' => 2, - 'total_one_time'=> GIFT_LEVEL_ONE_TIME, - 'total_recurring' => GIFT_LEVEL_RECURRING - }]) - + { + "name" => CAMPAIGN_GIFT_OPTION_NAME, + "total_donations" => 2, + "total_one_time" => GIFT_LEVEL_ONE_TIME, + "total_recurring" => GIFT_LEVEL_RECURRING + } + ]) end end diff --git a/spec/lib/query/query_campaign_metrics_spec.rb b/spec/lib/query/query_campaign_metrics_spec.rb index b4abd6ab4..7fe8e1d3a 100644 --- a/spec/lib/query/query_campaign_metrics_spec.rb +++ b/spec/lib/query/query_campaign_metrics_spec.rb @@ -1,26 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QueryCampaignMetrics do - describe 'calculates your metrics plus children' do - let(:nonprofit) {force_create(:nonprofit)} - let(:campaign) {force_create(:campaign, nonprofit:nonprofit, show_total_count:false, show_total_raised: false, goal_amount: 16000)} - let(:campaign_child) {force_create(:campaign, nonprofit:nonprofit, parent_campaign:campaign, show_total_count:true, show_total_raised: true, goal_amount: 8000)} + describe "calculates your metrics plus children" do + let(:nonprofit) { force_create(:nonprofit) } + let(:campaign) { force_create(:campaign, nonprofit: nonprofit, show_total_count: false, show_total_raised: false, goal_amount: 16000) } + let(:campaign_child) { force_create(:campaign, nonprofit: nonprofit, parent_campaign: campaign, show_total_count: true, show_total_raised: true, goal_amount: 8000) } - let(:campaign_child_2) {force_create(:campaign, nonprofit:nonprofit, parent_campaign:campaign, show_total_count:true, show_total_raised: true, goal_amount: 4000 )} + let(:campaign_child_2) { force_create(:campaign, nonprofit: nonprofit, parent_campaign: campaign, show_total_count: true, show_total_raised: true, goal_amount: 4000) } - let(:donation) { force_create(:donation, campaign: campaign, amount: 1000)} - let(:payment) { force_create(:payment, donation: donation, gross_amount:1000)} + let(:donation) { force_create(:donation, campaign: campaign, amount: 1000) } + let(:payment) { force_create(:payment, donation: donation, gross_amount: 1000) } - let(:donation2) { force_create(:donation, campaign: campaign, amount: 2000)} - let(:payment2) { force_create(:payment, donation: donation2, gross_amount:2000)} + let(:donation2) { force_create(:donation, campaign: campaign, amount: 2000) } + let(:payment2) { force_create(:payment, donation: donation2, gross_amount: 2000) } - let(:donation3) { force_create(:donation, campaign: campaign_child, amount: 2000)} - let(:payment3) { force_create(:payment, donation: donation3, gross_amount:4000, kind:'RecurringPayment')} - let(:payment3_1) { force_create(:payment, donation: donation3, gross_amount:2000, kind:'RecurringPayment')} + let(:donation3) { force_create(:donation, campaign: campaign_child, amount: 2000) } + let(:payment3) { force_create(:payment, donation: donation3, gross_amount: 4000, kind: "RecurringPayment") } + let(:payment3_1) { force_create(:payment, donation: donation3, gross_amount: 2000, kind: "RecurringPayment") } - let(:donation4) { force_create(:donation, campaign: campaign_child_2, amount: 8000)} - let(:payment4) { force_create(:payment, donation: donation4, gross_amount:8000)} + let(:donation4) { force_create(:donation, campaign: campaign_child_2, amount: 8000) } + let(:payment4) { force_create(:payment, donation: donation4, gross_amount: 8000) } let(:payments) do payment @@ -30,7 +30,7 @@ payment4 end - let (:campaign_metric) do + let(:campaign_metric) do payments QueryCampaignMetrics.on_donations(campaign.id) end @@ -45,29 +45,28 @@ QueryCampaignMetrics.on_donations(campaign_child_2.id) end - it 'campaign metric is valid' do - expect(campaign_metric['supporters_count']).to eq 4 - expect(campaign_metric['total_raised']).to eq 15000 - expect(campaign_metric['goal_amount']).to eq 16000 - expect(campaign_metric['show_total_count']).to eq false - expect(campaign_metric['show_total_raised']).to eq false + it "campaign metric is valid" do + expect(campaign_metric["supporters_count"]).to eq 4 + expect(campaign_metric["total_raised"]).to eq 15000 + expect(campaign_metric["goal_amount"]).to eq 16000 + expect(campaign_metric["show_total_count"]).to eq false + expect(campaign_metric["show_total_raised"]).to eq false end - it 'campaign child metric is valid' do - expect(campaign_child_metric['supporters_count']).to eq 1 - expect(campaign_child_metric['total_raised']).to eq 4000 - expect(campaign_child_metric['goal_amount']).to eq 8000 - expect(campaign_child_metric['show_total_count']).to eq true - expect(campaign_child_metric['show_total_raised']).to eq true + it "campaign child metric is valid" do + expect(campaign_child_metric["supporters_count"]).to eq 1 + expect(campaign_child_metric["total_raised"]).to eq 4000 + expect(campaign_child_metric["goal_amount"]).to eq 8000 + expect(campaign_child_metric["show_total_count"]).to eq true + expect(campaign_child_metric["show_total_raised"]).to eq true end - - it 'campaign child 2metric is valid' do - expect(campaign_child_2_metric['supporters_count']).to eq 1 - expect(campaign_child_2_metric['total_raised']).to eq 8000 - expect(campaign_child_2_metric['goal_amount']).to eq 4000 - expect(campaign_child_2_metric['show_total_count']).to eq true - expect(campaign_child_2_metric['show_total_raised']).to eq true + it "campaign child 2metric is valid" do + expect(campaign_child_2_metric["supporters_count"]).to eq 1 + expect(campaign_child_2_metric["total_raised"]).to eq 8000 + expect(campaign_child_2_metric["goal_amount"]).to eq 4000 + expect(campaign_child_2_metric["show_total_count"]).to eq true + expect(campaign_child_2_metric["show_total_raised"]).to eq true end end end diff --git a/spec/lib/query/query_donations_spec.rb b/spec/lib/query/query_donations_spec.rb index 34088427f..5f35cd769 100644 --- a/spec/lib/query/query_donations_spec.rb +++ b/spec/lib/query/query_donations_spec.rb @@ -1,46 +1,45 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QueryDonations do + describe "campaign_export" do + let(:nonprofit) { force_create(:nonprofit) } + let(:supporter) { force_create(:supporter) } - describe 'campaign_export' do - let(:nonprofit) {force_create(:nonprofit)} - let(:supporter) {force_create(:supporter)} - - let(:profile_email) { 'something@profile_email.com'} + let(:profile_email) { "something@profile_email.com" } let(:profile) do u = force_create(:user, email: profile_email) - profile = force_create(:profile, user: u) + force_create(:profile, user: u) end - let(:campaign) {force_create(:campaign, nonprofit:nonprofit, show_total_count:false, show_total_raised: false, goal_amount: 16000, profile: profile)} + let(:campaign) { force_create(:campaign, nonprofit: nonprofit, show_total_count: false, show_total_raised: false, goal_amount: 16000, profile: profile) } - let(:profile_email1) { 'something1@profile_email.com'} + let(:profile_email1) { "something1@profile_email.com" } let(:profile1) { u = force_create(:user, email: profile_email1) - profile = force_create(:profile, user: u) + force_create(:profile, user: u) } - let(:campaign_child) {force_create(:campaign, nonprofit:nonprofit, parent_campaign:campaign, show_total_count:true, show_total_raised: true, goal_amount: 8000, profile: profile1)} + let(:campaign_child) { force_create(:campaign, nonprofit: nonprofit, parent_campaign: campaign, show_total_count: true, show_total_raised: true, goal_amount: 8000, profile: profile1) } - let(:profile_email2) { 'something2@profile_email.com'} + let(:profile_email2) { "something2@profile_email.com" } let(:profile2) { u = force_create(:user, email: profile_email2) - profile = force_create(:profile, user: u) + force_create(:profile, user: u) } - let(:campaign_child_2) {force_create(:campaign, nonprofit:nonprofit, parent_campaign:campaign, show_total_count:true, show_total_raised: true, goal_amount: 4000, profile: profile2 )} + let(:campaign_child_2) { force_create(:campaign, nonprofit: nonprofit, parent_campaign: campaign, show_total_count: true, show_total_raised: true, goal_amount: 4000, profile: profile2) } - let(:donation) { force_create(:donation, campaign: campaign, amount: 1000, supporter:supporter)} - let(:payment) { force_create(:payment, donation: donation, gross_amount:1000, supporter:supporter)} + let(:donation) { force_create(:donation, campaign: campaign, amount: 1000, supporter: supporter) } + let(:payment) { force_create(:payment, donation: donation, gross_amount: 1000, supporter: supporter) } - let(:donation2) { force_create(:donation, campaign: campaign, amount: 2000, supporter:supporter)} - let(:payment2) { force_create(:payment, donation: donation2, gross_amount:2000, supporter:supporter)} + let(:donation2) { force_create(:donation, campaign: campaign, amount: 2000, supporter: supporter) } + let(:payment2) { force_create(:payment, donation: donation2, gross_amount: 2000, supporter: supporter) } - let(:donation3) { force_create(:donation, campaign: campaign_child, amount: 2000, supporter:supporter)} - let(:payment3) { force_create(:payment, donation: donation3, gross_amount:4000, kind:'RecurringPayment', supporter:supporter)} - let(:payment3_1) { force_create(:payment, donation: donation3, gross_amount:2000, kind:'RecurringPayment', supporter:supporter)} - let(:recurring) {force_create(:recurring_donation, donation: donation3, amount: 2000, supporter:supporter)} + let(:donation3) { force_create(:donation, campaign: campaign_child, amount: 2000, supporter: supporter) } + let(:payment3) { force_create(:payment, donation: donation3, gross_amount: 4000, kind: "RecurringPayment", supporter: supporter) } + let(:payment3_1) { force_create(:payment, donation: donation3, gross_amount: 2000, kind: "RecurringPayment", supporter: supporter) } + let(:recurring) { force_create(:recurring_donation, donation: donation3, amount: 2000, supporter: supporter) } - let(:donation4) { force_create(:donation, campaign: campaign_child_2, amount: 8000, supporter:supporter)} - let(:payment4) { force_create(:payment, donation: donation4, gross_amount:8000, supporter:supporter)} + let(:donation4) { force_create(:donation, campaign: campaign_child_2, amount: 8000, supporter: supporter) } + let(:payment4) { force_create(:payment, donation: donation4, gross_amount: 8000, supporter: supporter) } let(:payments) do payment @@ -51,34 +50,32 @@ payment4 end - let (:campaign_export) do + let(:campaign_export) do payments QueryDonations.campaign_export(campaign.id) - end - it 'payment amounts get the first payment, not additional ones' do + it "payment amounts get the first payment, not additional ones" do export = vector_to_hash(campaign_export) - expect(export.map{|i| i['Amount']}).to match_array(['$10.00', '$20.00', '$40.00', '$80.00']) + expect(export.map { |i| i["Amount"] }).to match_array(["$10.00", "$20.00", "$40.00", "$80.00"]) end - it 'includes the campaign ids' do - export = vector_to_hash(campaign_export) - expect(export.map{|i| i['Campaign Id']}).to match_array([campaign.id, campaign.id, campaign_child.id, campaign_child_2.id]) - end + it "includes the campaign ids" do + export = vector_to_hash(campaign_export) + expect(export.map { |i| i["Campaign Id"] }).to match_array([campaign.id, campaign.id, campaign_child.id, campaign_child_2.id]) + end - it 'includes user email' do + it "includes user email" do export = vector_to_hash(campaign_export) - expect(export.map{|i| i['Campaign Creator Email']}).to match_array([profile_email, profile_email, profile_email1, profile_email2]) + expect(export.map { |i| i["Campaign Creator Email"] }).to match_array([profile_email, profile_email, profile_email1, profile_email2]) end end ## move to common area def vector_to_hash(vecs) - keys = vecs.first.to_a.map{|k| k.to_s.titleize} + keys = vecs.first.to_a.map { |k| k.to_s.titleize } - vecs.drop(1).map{|v| keys.zip(v).to_h} + vecs.drop(1).map { |v| keys.zip(v).to_h } end - end diff --git a/spec/lib/query/query_payments_spec.rb b/spec/lib/query/query_payments_spec.rb index dafd4aa31..b6b0fc57e 100644 --- a/spec/lib/query/query_payments_spec.rb +++ b/spec/lib/query/query_payments_spec.rb @@ -1,119 +1,110 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'support/payments_for_a_payout' +require "rails_helper" +require "support/payments_for_a_payout" describe QueryPayments do - before :each do - @nonprofit = force_create(:nonprofit, name: "npo1"); - @supporters = [ force_create(:supporter, name: "supporter-0", nonprofit: @nonprofit), - force_create(:supporter, name: "supporter-1", nonprofit: @nonprofit)] + @nonprofit = force_create(:nonprofit, name: "npo1") + @supporters = [force_create(:supporter, name: "supporter-0", nonprofit: @nonprofit), + force_create(:supporter, name: "supporter-1", nonprofit: @nonprofit)] - @payments = [force_create(:payment, gross_amount: 1000, fee_total: 99, net_amount: 901, supporter: @supporters[0], nonprofit:@nonprofit), - force_create(:payment, gross_amount: 2000, fee_total: 22, net_amount: 1978, supporter: @supporters[1], nonprofit:@nonprofit)] - @bank_account = force_create(:bank_account, name: 'baids_for_payoutnk1', nonprofit: @nonprofit) + @payments = [force_create(:payment, gross_amount: 1000, fee_total: 99, net_amount: 901, supporter: @supporters[0], nonprofit: @nonprofit), + force_create(:payment, gross_amount: 2000, fee_total: 22, net_amount: 1978, supporter: @supporters[1], nonprofit: @nonprofit)] + @bank_account = force_create(:bank_account, name: "baids_for_payoutnk1", nonprofit: @nonprofit) end - - describe '.ids_for_payout' do + describe ".ids_for_payout" do around(:each) do |example| - Timecop.freeze(2020,5,5) do + Timecop.freeze(2020, 5, 5) do example.run end end - describe 'no date provided' do - include_context 'payments for a payout' do + describe "no date provided" do + include_context "payments for a payout" do let(:nonprofit) { @nonprofit } end - let!(:payments) {payments_two_days_ago.concat(payments_yesterday).concat(payments_today)} + let!(:payments) { payments_two_days_ago.concat(payments_yesterday).concat(payments_today) } + + let!(:expected_payments) { available_payments_two_days_ago.concat(available_payments_yesterday).concat(available_payments_today) } - let!(:expected_payments) {available_payments_two_days_ago.concat(available_payments_yesterday).concat(available_payments_today)} - - it 'np is invalid' do + it "np is invalid" do expect(QueryPayments.ids_for_payout(686826812658102751098754)).to eq [] end - it 'works without a date provided' do + it "works without a date provided" do result = QueryPayments.ids_for_payout(nonprofit.id) - expect(result).to match_array(expected_payments.map{|i| i.id}) + expect(result).to match_array(expected_payments.map { |i| i.id }) end end - describe 'with date provided' do - include_context 'payments for a payout' do + describe "with date provided" do + include_context "payments for a payout" do let(:nonprofit) { @nonprofit } end - let!(:payments) {payments_two_days_ago.concat(payments_yesterday).concat(payments_today)} + let!(:payments) { payments_two_days_ago.concat(payments_yesterday).concat(payments_today) } - let!(:expected_payments) {available_payments_two_days_ago.concat(available_payments_yesterday)} + let!(:expected_payments) { available_payments_two_days_ago.concat(available_payments_yesterday) } - it 'np is invalid' do + it "np is invalid" do expect(QueryPayments.ids_for_payout(686826812658102751098754)).to eq [] end - it 'works with a date provided' do + it "works with a date provided" do result = QueryPayments.ids_for_payout(nonprofit.id, { - date: Time.current - 1.day + 1.hour #the payments are all at 1AM + date: 1.day.ago + 1.hour # the payments are all at 1AM }) - expect(result).to match_array(expected_payments.map{|i| i.id}) + expect(result).to match_array(expected_payments.map { |i| i.id }) end end - - - end - describe '.get_payout_total'do + describe ".get_payout_total" do around(:each) do |example| - Timecop.freeze(2020,5,5) do + Timecop.freeze(2020, 5, 5) do example.run end end - include_context 'payments for a payout' do + include_context "payments for a payout" do let(:nonprofit) { @nonprofit } - end - - it 'gives empty payout result if no payments provided' do + + it "gives empty payout result if no payments provided" do result = QueryPayments.get_payout_totals([]) - expected = {'gross_amount' => 0, 'fee_total' => 0, 'net_amount' => 0} + expected = {"gross_amount" => 0, "fee_total" => 0, "net_amount" => 0} expect(result).to eq expected end - it 'gives correct payout info' do + it "gives correct payout info" do entities_yesterday result = QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(nonprofit.id)) - expected = {gross_amount: 57900, fee_total: -5000, net_amount: 52900, count: 18}.with_indifferent_access + expected = {gross_amount: 57900, fee_total: -5000, net_amount: 52900, count: 18}.with_indifferent_access expect(result.with_indifferent_access).to eq expected end - - end - describe '.full_search' do - + describe ".full_search" do include_context :shared_rd_donation_value_context before(:each) do - nonprofit.stripe_account_id = Stripe::Account.create()['id'] + nonprofit.stripe_account_id = Stripe::Account.create["id"] nonprofit.save! - cust = Stripe::Customer.create() + cust = Stripe::Customer.create card.stripe_customer_id = cust.id - source = Stripe::Customer.create_source(cust.id, {source: StripeMockHelper.generate_card_token(brand: 'Visa', country: 'US')}) + source = Stripe::Customer.create_source(cust.id, {source: StripeMockHelper.generate_card_token(brand: "Visa", country: "US")}) card.stripe_card_id = source.id card.save! - expect(Stripe::Charge).to receive(:create).exactly(3).times.and_wrap_original {|m, *args| a = m.call(*args); - @stripe_charge_id = a['id'] + expect(Stripe::Charge).to receive(:create).exactly(3).times.and_wrap_original { |m, *args| + a = m.call(*args) + @stripe_charge_id = a["id"] a } - end - let(:charge_amount_small) { 200} - let(:charge_amount_medium) { 400} - let(:charge_amount_large) { 600} + let(:charge_amount_small) { 200 } + let(:charge_amount_medium) { 400 } + let(:charge_amount_large) { 600 } def generate_offsite_donation(h) date = h[:date] @@ -123,106 +114,93 @@ def generate_offsite_donation(h) nonprofit_id: nonprofit.id, supporter_id: supporter.id, date: date, - dedication: 'dedication', - designation: 'designation' - }.with_indifferent_access + dedication: "dedication", + designation: "designation" + }.with_indifferent_access InsertDonation.offsite(input) end def generate_donation(h) - input = h.merge( + input = h.merge( nonprofit_id: nonprofit.id, supporter_id: supporter.id, - dedication: 'dedication', - designation: 'designation' - ) + dedication: "dedication", + designation: "designation" + ) d = InsertDonation.with_stripe(input) - c = Charge.find(d['charge']['id']) + c = Charge.find(d["charge"]["id"]) c.created_at = h[:date] c.updated_at = h[:date] c.save! d end + let(:amount_of_fees_to_refund) { 0 } + let(:stripe_app_fee_refund) { Stripe::ApplicationFeeRefund.construct_from({amount: amount_of_fees_to_refund, id: "app_fee_refund_1"}) } + let(:stripe_refund) { Stripe::Refund.construct_from({id: "refund_1"}) } - let(:amount_of_fees_to_refund) { 0} - let(:stripe_app_fee_refund) { Stripe::ApplicationFeeRefund.construct_from({amount: amount_of_fees_to_refund, id: 'app_fee_refund_1'})} - let(:stripe_refund) { Stripe::Refund.construct_from({id: 'refund_1'})} - let(:perform_stripe_refund_result) do - {stripe_refund: stripe_refund, stripe_app_fee_refund: amount_of_fees_to_refund > 0 ? stripe_app_fee_refund : nil} + {stripe_refund: stripe_refund, stripe_app_fee_refund: (amount_of_fees_to_refund > 0) ? stripe_app_fee_refund : nil} end - describe 'general donations' do - let(:offsite_donation ) { + describe "general donations" do + let(:offsite_donation) { generate_offsite_donation(amount: charge_amount_small, date: (Time.now - 1.day).to_s) } let(:donation_result_yesterday) { - generate_donation(amount: charge_amount_small, - - token: source_tokens[0].token, - date: (Time.now - 1.day).to_s) - + generate_donation(amount: charge_amount_small, + token: source_tokens[0].token, + date: (Time.now - 1.day).to_s) } let(:donation_result_today) { - generate_donation(amount: charge_amount_medium, - token: source_tokens[1].token, + token: source_tokens[1].token, - date: (Time.now).to_s, - fee_covered: true - ) - - + date: Time.now.to_s, + fee_covered: true) } let(:donation_result_tomorrow) { - generate_donation(amount: charge_amount_large, - token: source_tokens[2].token, - date: (Time.now + 1.day).to_s, - fee_covered: false - ) - - - + token: source_tokens[2].token, + date: (Time.now + 1.day).to_s, + fee_covered: false) } let(:charge_result_yesterday) { - Charge.find(donation_result_yesterday['charge']['id']) + Charge.find(donation_result_yesterday["charge"]["id"]) } - let (:first_refund_of_yesterday) { - charge = charge_result_yesterday + let(:first_refund_of_yesterday) { + charge = charge_result_yesterday expect(InsertRefunds).to receive(:perform_stripe_refund).with( - nonprofit_id:nonprofit.id, refund_data:{ - 'amount' => 100, - 'charge'=> charge.stripe_charge_id - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) + nonprofit_id: nonprofit.id, refund_data: { + "amount" => 100, + "charge" => charge.stripe_charge_id + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) expect(InsertActivities).to receive(:for_refunds) - InsertRefunds.with_stripe(charge.attributes, {amount: 100}.with_indifferent_access) - + InsertRefunds.with_stripe(charge.attributes, {amount: 100}.with_indifferent_access) } let(:second_refund_of_yesterday) { - charge = charge_result_yesterday + charge = charge_result_yesterday expect(InsertRefunds).to receive(:perform_stripe_refund).with( - nonprofit_id: nonprofit.id, refund_data:{ - 'amount' => 50, - 'charge'=> charge.stripe_charge_id - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) + nonprofit_id: nonprofit.id, refund_data: { + "amount" => 50, + "charge" => charge.stripe_charge_id + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) expect(InsertActivities).to receive(:for_refunds) InsertRefunds.with_stripe(charge.attributes, {amount: 50}.with_indifferent_access) - } - - it 'empty filter returns all' do + it "empty filter returns all" do offsite_donation donation_result_yesterday donation_result_today @@ -230,329 +208,337 @@ def generate_donation(h) first_refund_of_yesterday second_refund_of_yesterday - result = QueryPayments::full_search(nonprofit.id, {}) + result = QueryPayments.full_search(nonprofit.id, {}) expect(result[:data].count).to eq 6 end - context 'considering the nonprofit timezone on the query result' do + context "considering the nonprofit timezone on the query result" do before do donation_result_today first_refund_of_yesterday second_refund_of_yesterday end - it 'when the nonprofit does not have a timezone it considers UTC as default' do + it "when the nonprofit does not have a timezone it considers UTC as default" do donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, {}) - expect(result[:data].first['date']).to eq (Time.now).to_s + result = QueryPayments.full_search(nonprofit.id, {}) + expect(result[:data].first["date"]).to eq Time.now.to_s end - context 'when the nonprofit has a timezone' do + context "when the nonprofit has a timezone" do before do - nonprofit.update_attributes(timezone: 'America/New_York') + nonprofit.update_attributes(timezone: "America/New_York") allow(QuerySourceToken) .to receive(:get_and_increment_source_token) .and_return(source_tokens[0]) end - it 'shows the corresponding time' do + it "shows the corresponding time" do donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, {}) - expect(result[:data].first['date']).to eq ((Time.now) - 4.hours).to_s + result = QueryPayments.full_search(nonprofit.id, {}) + expect(result[:data].first["date"]).to eq (Time.now - 4.hours).to_s end - it 'finds the payments on dates after the specified dates' do + it "finds the payments on dates after the specified dates" do donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { after_date: Time.now - 4.hours }) + result = QueryPayments.full_search(nonprofit.id, {after_date: Time.now - 4.hours}) expect(result[:data].count).to eq 5 end - it 'finds the payments on dates before the specified dates' do + it "finds the payments on dates before the specified dates" do donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { before_date: Time.now }) + result = QueryPayments.full_search(nonprofit.id, {before_date: Time.now}) expect(result[:data].count).to eq 5 end - it 'finds the payments of an specific year' do + it "finds the payments of an specific year" do # creating a payment at 1 AM UTC from january 2020 # should not be included in the 2020 query if we are at America/New_York - Timecop.freeze(2020,1,1,1,0,0, "+00:00") - donation = - generate_donation( - amount: charge_amount_large, - token: source_tokens[2].token, - date: Time.now.to_s - ) - result_for_2020 = QueryPayments::full_search(nonprofit.id, { year: '2020' }) - result_for_2019 = QueryPayments::full_search(nonprofit.id, { year: '2019' }) + Timecop.freeze(2020, 1, 1, 1, 0, 0, "+00:00") + generate_donation( + amount: charge_amount_large, + token: source_tokens[2].token, + date: Time.now.to_s + ) + result_for_2020 = QueryPayments.full_search(nonprofit.id, {year: "2020"}) + result_for_2019 = QueryPayments.full_search(nonprofit.id, {year: "2019"}) expect(result_for_2019[:data].count).to eq 1 expect(result_for_2020[:data].count).to eq 4 end end end - context 'filtering by donation or supporter fields' do - let(:input) {{ - amount: 100, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - token: source_tokens[4].token, - date: (Time.now - 1.day).to_s, - comment: 'donation comment', - dedication: 'dedication', - designation: 'designation' - }} + context "filtering by donation or supporter fields" do + let(:input) { + { + amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + token: source_tokens[4].token, + date: (Time.now - 1.day).to_s, + comment: "donation comment", + dedication: "dedication", + designation: "designation" + } + } - it 'searching for a payment using the donation comment' do + it "searching for a payment using the donation comment" do InsertDonation.with_stripe(input) donation_result_tomorrow donation_result_yesterday - result = QueryPayments::full_search(nonprofit.id, { search: 'donation comment' }) + result = QueryPayments.full_search(nonprofit.id, {search: "donation comment"}) expect(result[:data].count).to eq 1 end - it 'searching for a payment using the supporter name' do + it "searching for a payment using the supporter name" do InsertDonation.with_stripe(input) donation_result_tomorrow donation_result_yesterday - result = QueryPayments::full_search(nonprofit.id, { search: supporter.name }) + result = QueryPayments.full_search(nonprofit.id, {search: supporter.name}) expect(result[:data].count).to eq 3 end end - context 'when filtering by payment id' do - let(:input) {{ - amount: 100, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - token: source_tokens[4].token, - date: (Time.now - 1.day).to_s, - comment: 'donation comment', - dedication: 'dedication', - designation: 'designation' - }} + context "when filtering by payment id" do + let(:input) { + { + amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + token: source_tokens[4].token, + date: (Time.now - 1.day).to_s, + comment: "donation comment", + dedication: "dedication", + designation: "designation" + } + } - it 'returns one result' do + it "returns one result" do InsertDonation.with_stripe(input) donation_result_tomorrow donation_result_yesterday - result = QueryPayments::full_search(nonprofit.id, { search: Payment.last.id }) + result = QueryPayments.full_search(nonprofit.id, {search: Payment.last.id}) expect(result[:data].count).to eq 1 end end - context 'when the search includes a number that is not a payment ID' do - let(:input) {{ - amount: 100, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - token: source_tokens[4].token, - date: (Time.now - 1.day).to_s, - comment: '2020', - dedication: 'dedication', - designation: 'designation' - }} + context "when the search includes a number that is not a payment ID" do + let(:input) { + { + amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + token: source_tokens[4].token, + date: (Time.now - 1.day).to_s, + comment: "2020", + dedication: "dedication", + designation: "designation" + } + } - it 'returns one result' do + it "returns one result" do InsertDonation.with_stripe(input) donation_result_tomorrow donation_result_yesterday - result = QueryPayments::full_search(nonprofit.id, { search: 2020 }) + result = QueryPayments.full_search(nonprofit.id, {search: 2020}) expect(result[:data].count).to eq 1 end end - context 'when searching by supporter phone number' do - it 'finds when using character filled phone number' do + context "when searching by supporter phone number" do + it "finds when using character filled phone number" do donation_result_yesterday donation_result_today donation_result_tomorrow supporter.phone = "+1 (920) 915-4980" supporter.save! - - result = QueryPayments::full_search(nonprofit.id, { search: "+1(920) 915*4980a" }) + + result = QueryPayments.full_search(nonprofit.id, {search: "+1(920) 915*4980a"}) expect(result[:data].count).to eq 3 end - - it 'finds when using spaced phone number' do + + it "finds when using spaced phone number" do donation_result_yesterday donation_result_today donation_result_tomorrow supporter.phone = "+1 (920) 915-4980" supporter.save! - result = QueryPayments::full_search(nonprofit.id, { search: "1 920 915 4980" }) + result = QueryPayments.full_search(nonprofit.id, {search: "1 920 915 4980"}) expect(result[:data].count).to eq 3 end - - it 'finds when using nonspaced phone number' do + + it "finds when using nonspaced phone number" do donation_result_yesterday donation_result_today donation_result_tomorrow supporter.phone = "+1 (920) 915-4980" supporter.save! - result = QueryPayments::full_search(nonprofit.id, { search: "19209154980" }) + result = QueryPayments.full_search(nonprofit.id, {search: "19209154980"}) expect(result[:data].count).to eq 3 end - - it 'does not find based on partial phone number' do + + it "does not find based on partial phone number" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { search: "9209154980" }) + result = QueryPayments.full_search(nonprofit.id, {search: "9209154980"}) expect(result[:data].count).to eq 0 # just the headers end - it 'does not find payments with blank phone numbers accidentally' do + it "does not find payments with blank phone numbers accidentally" do donation_result_yesterday donation_result_today donation_result_tomorrow supporter.phone = " " supporter.save! - result = QueryPayments::full_search(nonprofit.id, { search: "A search term" }) + result = QueryPayments.full_search(nonprofit.id, {search: "A search term"}) expect(result[:data].count).to eq 0 - end end - context 'when filtering by anonymous or not anonymous donations' do - context 'when supporter and donation are not anonymous' do - context 'when not filtering' do - it 'finds all results' do + context "when filtering by anonymous or not anonymous donations" do + context "when supporter and donation are not anonymous" do + context "when not filtering" do + it "finds all results" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: '' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: ""}) expect(result[:data].count).to eq 3 end end - context 'when filtering by anonymous' do - it 'does not find results' do + context "when filtering by anonymous" do + it "does not find results" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'true' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "true"}) expect(result[:data].count).to eq 0 end end - context 'when filtering by not-anonymous' do - it 'finds all results' do + context "when filtering by not-anonymous" do + it "finds all results" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'false' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "false"}) expect(result[:data].count).to eq 3 end end end - context 'when supporter is anonymous but donation is not' do + context "when supporter is anonymous but donation is not" do before do supporter.anonymous = true supporter.save! end - context 'when not filtering' do - it 'finds all results' do + context "when not filtering" do + it "finds all results" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: '' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: ""}) expect(result[:data].count).to eq 3 end end - context 'when filtering by anonymous' do - it 'finds all results' do + context "when filtering by anonymous" do + it "finds all results" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'true' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "true"}) expect(result[:data].count).to eq 3 end end - context 'when filtering by not-anonymous' do - it 'does not find results' do + context "when filtering by not-anonymous" do + it "does not find results" do donation_result_yesterday donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'false' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "false"}) expect(result[:data].count).to eq 0 end end end - context 'when supporter is not anonymous but donation is' do - let(:input) {{ - amount: 100, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - token: source_tokens[4].token, - date: (Time.now - 1.day).to_s, - comment: 'donation comment', - designation: 'designation', - anonymous: true - }} + context "when supporter is not anonymous but donation is" do + let(:input) { + { + amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + token: source_tokens[4].token, + date: (Time.now - 1.day).to_s, + comment: "donation comment", + designation: "designation", + anonymous: true + } + } before do InsertDonation.with_stripe(input) end - context 'when not filtering' do - it 'finds all results' do + context "when not filtering" do + it "finds all results" do donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: '' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: ""}) expect(result[:data].count).to eq 3 end end - context 'when filtering by anonymous' do - it 'finds all results' do + context "when filtering by anonymous" do + it "finds all results" do donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'true' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "true"}) expect(result[:data].count).to eq 1 end end - context 'when filtering by not-anonymous' do - it 'does not find results' do + context "when filtering by not-anonymous" do + it "does not find results" do donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'false' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "false"}) expect(result[:data].count).to eq 2 end end end - context 'when supporter and donation are anonymous' do - let(:input) {{ - amount: 100, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - token: source_tokens[4].token, - date: (Time.now - 1.day).to_s, - comment: 'donation comment', - designation: 'designation', - anonymous: true - }} + context "when supporter and donation are anonymous" do + let(:input) { + { + amount: 100, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + token: source_tokens[4].token, + date: (Time.now - 1.day).to_s, + comment: "donation comment", + designation: "designation", + anonymous: true + } + } before do supporter.anonymous = true @@ -560,383 +546,362 @@ def generate_donation(h) InsertDonation.with_stripe(input) end - context 'when not filtering' do - it 'finds all results' do + context "when not filtering" do + it "finds all results" do donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: '' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: ""}) expect(result[:data].count).to eq 3 end end - context 'when filtering by anonymous' do - it 'finds all results' do + context "when filtering by anonymous" do + it "finds all results" do donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'true' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "true"}) expect(result[:data].count).to eq 3 end end - context 'when filtering by not-anonymous' do - it 'does not find results' do + context "when filtering by not-anonymous" do + it "does not find results" do donation_result_today donation_result_tomorrow - result = QueryPayments::full_search(nonprofit.id, { anonymous: 'false' }) + result = QueryPayments.full_search(nonprofit.id, {anonymous: "false"}) expect(result[:data].count).to eq 0 end end end end - context 'when filtering by online only' do - it 'has 3' do + context "when filtering by online only" do + it "has 3" do offsite_donation donation_result_yesterday donation_result_today donation_result_tomorrow first_refund_of_yesterday second_refund_of_yesterday - result = QueryPayments::full_search(nonprofit.id, {online_payments_only: true}) + result = QueryPayments.full_search(nonprofit.id, {online_payments_only: true}) expect(result[:data].count).to eq 3 end end - context 'when filtering by fee coverage' do - it 'has 1 when filtering by fee is covered by supporter' do + context "when filtering by fee coverage" do + it "has 1 when filtering by fee is covered by supporter" do offsite_donation donation_result_yesterday donation_result_today donation_result_tomorrow first_refund_of_yesterday second_refund_of_yesterday - result = QueryPayments::full_search(nonprofit.id, {supporter_covered_fee: true}) - + result = QueryPayments.full_search(nonprofit.id, {supporter_covered_fee: true}) + expect(result[:data].count).to eq 1 end - - it 'has 5 when filtering by fee NOT covered by supporter' do + + it "has 5 when filtering by fee NOT covered by supporter" do offsite_donation donation_result_yesterday donation_result_today donation_result_tomorrow first_refund_of_yesterday second_refund_of_yesterday - result = QueryPayments::full_search(nonprofit.id, {supporter_covered_fee: false}) - + result = QueryPayments.full_search(nonprofit.id, {supporter_covered_fee: false}) + expect(result[:data].count).to eq 5 end end - context 'when filtering by supporter tag' do - it 'has 2' do + context "when filtering by supporter tag" do + it "has 2" do offsite_donation donation_result_yesterday donation_result_today donation_result_tomorrow - supporter = Supporter.find(offsite_donation[:json]['payment']['supporter_id']) - tag_master = create(:tag_master_base, nonprofit:Nonprofit.find(offsite_donation[:json]['payment']['nonprofit_id'])) + supporter = Supporter.find(offsite_donation[:json]["payment"]["supporter_id"]) + tag_master = create(:tag_master_base, nonprofit: Nonprofit.find(offsite_donation[:json]["payment"]["nonprofit_id"])) supporter.tag_joins.create(tag_master: tag_master) - result = QueryPayments::full_search(nonprofit.id, {tag_master_id: tag_master.id}) + result = QueryPayments.full_search(nonprofit.id, {tag_master_id: tag_master.id}) expect(result[:data].count).to eq 4 end - it 'has 0 for different tag' do + it "has 0 for different tag" do offsite_donation donation_result_yesterday donation_result_today donation_result_tomorrow - supporter = Supporter.find(offsite_donation[:json]['payment']['supporter_id']) - tag_master = create(:tag_master_base, nonprofit:Nonprofit.find(offsite_donation[:json]['payment']['nonprofit_id'])) - result = QueryPayments::full_search(nonprofit.id, {tag_master_id: tag_master.id}) + Supporter.find(offsite_donation[:json]["payment"]["supporter_id"]) + tag_master = create(:tag_master_base, nonprofit: Nonprofit.find(offsite_donation[:json]["payment"]["nonprofit_id"])) + result = QueryPayments.full_search(nonprofit.id, {tag_master_id: tag_master.id}) expect(result[:data].count).to eq 0 end end - end - describe 'event donations' do + describe "event donations" do let(:donation_result_yesterday) { generate_donation(amount: charge_amount_small, - event_id: event.id, - token: source_tokens[0].token, - date: (Time.now - 1.day).to_s) - - + event_id: event.id, + token: source_tokens[0].token, + date: (Time.now - 1.day).to_s) } let(:donation_result_today) { - generate_donation(amount: charge_amount_medium, - event_id: event.id, - token: source_tokens[1].token, + event_id: event.id, + token: source_tokens[1].token, - date: (Time.now).to_s - ) + date: Time.now.to_s) } let(:donation_result_tomorrow) { - generate_donation(amount: charge_amount_large, - token: source_tokens[2].token, - date: (Time.now - 1.day).to_s - ) - + token: source_tokens[2].token, + date: (Time.now - 1.day).to_s) } let(:charge_result_yesterday) { - Charge.find(donation_result_yesterday['charge']['id']) + Charge.find(donation_result_yesterday["charge"]["id"]) } - - let (:first_refund_of_yesterday) { - charge = charge_result_yesterday + let(:first_refund_of_yesterday) { + charge = charge_result_yesterday expect(InsertRefunds).to receive(:perform_stripe_refund).with( - nonprofit_id: nonprofit.id, refund_data:{ - 'amount' => 100, - 'charge'=> charge.stripe_charge_id - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) + nonprofit_id: nonprofit.id, refund_data: { + "amount" => 100, + "charge" => charge.stripe_charge_id + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) expect(InsertActivities).to receive(:for_refunds) InsertRefunds.with_stripe(charge.attributes, {amount: 100}.with_indifferent_access) - } let(:second_refund_of_yesterday) { - charge = charge_result_yesterday + charge = charge_result_yesterday expect(InsertRefunds).to receive(:perform_stripe_refund).with( - nonprofit_id:nonprofit.id, refund_data:{ - 'amount' => 50, - 'charge'=> charge.stripe_charge_id - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) + nonprofit_id: nonprofit.id, refund_data: { + "amount" => 50, + "charge" => charge.stripe_charge_id + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) expect(InsertActivities).to receive(:for_refunds) InsertRefunds.with_stripe(charge.attributes, {amount: 50}.with_indifferent_access) - } - it 'search includes refunds for that event ' do + it "search includes refunds for that event " do donation_result_yesterday donation_result_today donation_result_tomorrow first_refund_of_yesterday second_refund_of_yesterday - result = QueryPayments::full_search(nonprofit.id, {event_id: event.id}) + result = QueryPayments.full_search(nonprofit.id, {event_id: event.id}) expect(result[:data].count).to eq 4 - expect(result[:data]).to_not satisfy {|i| i.any?{|j| j['id'] == donation_result_tomorrow['payment']['id']}} + expect(result[:data]).to_not satisfy { |i| i.any? { |j| j["id"] == donation_result_tomorrow["payment"]["id"] } } end end - describe 'campaign donations' do + describe "campaign donations" do let(:donation_result_yesterday) { generate_donation(amount: charge_amount_small, - campaign_id:campaign.id, - token: source_tokens[0].token, - date: (Time.now - 1.day).to_s) - - + campaign_id: campaign.id, + token: source_tokens[0].token, + date: (Time.now - 1.day).to_s) } let(:charge_result_yesterday) { - Charge.find(donation_result_yesterday['charge']['id']) + Charge.find(donation_result_yesterday["charge"]["id"]) } let(:donation_result_today) { - generate_donation(amount: charge_amount_medium, - campaign_id:campaign.id, - token: source_tokens[1].token, + campaign_id: campaign.id, + token: source_tokens[1].token, - date: (Time.now).to_s - ) + date: Time.now.to_s) } let(:charge_result_today) { - Charge.find(donation_result_today['charge']['id']) + Charge.find(donation_result_today["charge"]["id"]) } - let(:donation_result_tomorrow) { - generate_donation(amount: charge_amount_large, - token: source_tokens[2].token, - date: (Time.now - 1.day).to_s - ) - + token: source_tokens[2].token, + date: (Time.now - 1.day).to_s) } let(:charge_result_tomorrow) { - Charge.find(donation_result_tomorrow['charge']['id']) + Charge.find(donation_result_tomorrow["charge"]["id"]) } - let(:amount_of_fees_to_refund) { 0} - let(:stripe_app_fee_refund) { Stripe::ApplicationFeeRefund.construct_from({amount: amount_of_fees_to_refund, id: 'app_fee_refund_1'})} - let(:stripe_refund) { Stripe::Refund.construct_from({id: 'refund_1'})} - + let(:amount_of_fees_to_refund) { 0 } + let(:stripe_app_fee_refund) { Stripe::ApplicationFeeRefund.construct_from({amount: amount_of_fees_to_refund, id: "app_fee_refund_1"}) } + let(:stripe_refund) { Stripe::Refund.construct_from({id: "refund_1"}) } + let(:perform_stripe_refund_result) do - {stripe_refund: stripe_refund, stripe_app_fee_refund: amount_of_fees_to_refund > 0 ? stripe_app_fee_refund : nil} + {stripe_refund: stripe_refund, stripe_app_fee_refund: (amount_of_fees_to_refund > 0) ? stripe_app_fee_refund : nil} end let(:first_refund_of_yesterday) { - charge = charge_result_yesterday + charge = charge_result_yesterday expect(InsertRefunds).to receive(:perform_stripe_refund).with( nonprofit_id: nonprofit.id, refund_data: { - 'amount' => 100, - 'charge'=> charge.stripe_charge_id - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) - - InsertRefunds.with_stripe(charge.attributes, {amount: 100}.with_indifferent_access) + "amount" => 100, + "charge" => charge.stripe_charge_id + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) + InsertRefunds.with_stripe(charge.attributes, {amount: 100}.with_indifferent_access) } let(:second_refund_of_yesterday) { - charge = charge_result_yesterday + charge = charge_result_yesterday expect(InsertRefunds).to receive(:perform_stripe_refund).with( nonprofit_id: nonprofit.id, refund_data: { - 'amount' => 50, - 'charge'=> charge.stripe_charge_id - }, charge_date: charge.created_at).and_return(perform_stripe_refund_result) + "amount" => 50, + "charge" => charge.stripe_charge_id + }, charge_date: charge.created_at + ).and_return(perform_stripe_refund_result) expect(InsertActivities).to receive(:for_refunds) InsertRefunds.with_stripe(charge.attributes, {amount: 50}.with_indifferent_access) - } - - it 'search includes refunds for that campaign ' do + it "search includes refunds for that campaign " do donation_result_yesterday donation_result_today donation_result_tomorrow first_refund_of_yesterday second_refund_of_yesterday - result = QueryPayments::full_search(nonprofit.id, {campaign_id: campaign.id}) + result = QueryPayments.full_search(nonprofit.id, {campaign_id: campaign.id}) expect(result[:data].count).to eq 4 - expect(result[:data]).to_not satisfy {|i| i.any?{|j| j['id'] == donation_result_tomorrow['payment']['id']}} + expect(result[:data]).to_not satisfy { |i| i.any? { |j| j["id"] == donation_result_tomorrow["payment"]["id"] } } end end - end - describe 'balances and payouts' do - include_context 'payments for a payout' do - let(:nonprofit) {create(:nonprofit)} + describe "balances and payouts" do + include_context "payments for a payout" do + let(:nonprofit) { create(:nonprofit) } end - - let(:nonprofit_balances) { QueryPayments.nonprofit_balances(nonprofit.id)} + let(:nonprofit_balances) { QueryPayments.nonprofit_balances(nonprofit.id) } before(:each) do entities_today end - describe ".nonprofit_balances" do - - it 'has a correct pending balance' do - expect(nonprofit_balances['pending']).to eq('net' => eb_today.stats[:pending_net], 'gross' => eb_today.stats[:pending_gross]) + describe ".nonprofit_balances" do + it "has a correct pending balance" do + expect(nonprofit_balances["pending"]).to eq("net" => eb_today.stats[:pending_net], "gross" => eb_today.stats[:pending_gross]) end - it 'has a correct available balance' do - expect(nonprofit_balances['available']).to eq('net' => eb_today.stats[:net_amount], 'gross' => eb_today.stats[:gross_amount]) + it "has a correct available balance" do + expect(nonprofit_balances["available"]).to eq("net" => eb_today.stats[:net_amount], "gross" => eb_today.stats[:gross_amount]) end end - - describe '.for_payout' do - let(:payments) do + + describe ".for_payout" do + let(:payments) do [ - entities_today[:legacy_dispute_paid].dispute_transactions.first.payment, + entities_today[:legacy_dispute_paid].dispute_transactions.first.payment, entities_today[:dispute_paid].dispute_transactions.first.payment, entities_today[:charge_paid].payment, - entities_today[:refund_disbursed].payment, + entities_today[:refund_disbursed].payment ] end - let(:payment_not_paid_out_payment) do + let(:payment_not_paid_out_payment) do entities_yesterday[:charge_paid] end let(:payout) do - force_create(:payout, - gross_amount:payments.sum{|i| i.gross_amount}, - fee_total: payments.sum{|i| i.fee_total}, - net_amount: payments.sum{|i| i.net_amount}, - nonprofit: nonprofit) + force_create(:payout, + gross_amount: payments.sum { |i| i.gross_amount }, + fee_total: payments.sum { |i| i.fee_total }, + net_amount: payments.sum { |i| i.net_amount }, + nonprofit: nonprofit) end let(:payment_payouts) do - payments.map{|p| force_create(:payment_payout, payment: p, payout:payout)} + payments.map { |p| force_create(:payment_payout, payment: p, payout: payout) } end - let(:bank_account) do + let(:bank_account) do force_create(:bank_account, name: "bank", nonprofit: nonprofit) end - let(:result) do + let(:result) do payment_not_paid_out_payment QueryPayments.for_payout(nonprofit.id, payout.id) end - + before(:each) do bank_account payment_payouts end - - it 'sets the correct headers' do + + it "sets the correct headers" do expect(result.first).to eq(["date", "gross_total", "fee_total", "net_total", "bank_name", "status"]) end - - it 'sets the correct payout data' do + + it "sets the correct payout data" do expect(result[1].count).to eq(6) # TODO end - it 'sets the correct number of rows' do + it "sets the correct number of rows" do expect(result.count).to eq 8 # the payout header, the payout data, an empty row, the payment headers, the four paid out payments end - - it 'sets the payment headers', :pending => true do + + it "sets the payment headers", pending: true do expect(result[3]).to eq(["Date", "Gross Amount", "Fee Total", "Net Amount", "Type", "Payment ID", "Last Name", "First Name", "Full Name", "Organization", "Email", "Phone", "Address", "City", "State", "Postal Code", "Country", "Anonymous?", "Designation", "Honorarium/Memorium", "Comment", "Campaign", "Campaign Gift Level", "Event"]) end - - it 'sets the correct payment data', :pending => true do + + it "sets the correct payment data", pending: true do expect(result[4].count).to eq 24 end end - describe '.full_search' do - let(:payments) do + describe ".full_search" do + let(:payments) do [ - entities_today[:legacy_dispute_paid].dispute_transactions.first.payment, + entities_today[:legacy_dispute_paid].dispute_transactions.first.payment, entities_today[:dispute_paid].dispute_transactions.first.payment, entities_today[:charge_paid].payment, - entities_today[:refund_disbursed].payment, + entities_today[:refund_disbursed].payment ] end let(:payout) do - force_create(:payout, - gross_amount:payments.sum{|i| i.gross_amount}, - fee_total: payments.sum{|i| i.fee_total}, - net_amount: payments.sum{|i| i.net_amount}, - nonprofit: nonprofit) + force_create(:payout, + gross_amount: payments.sum { |i| i.gross_amount }, + fee_total: payments.sum { |i| i.fee_total }, + net_amount: payments.sum { |i| i.net_amount }, + nonprofit: nonprofit) end let(:payment_payouts) do - payments.map{|p| force_create(:payment_payout, payment: p, payout:payout)} + payments.map { |p| force_create(:payment_payout, payment: p, payout: payout) } end - let(:bank_account) do + let(:bank_account) do force_create(:bank_account, name: "bank", nonprofit: nonprofit) end - let(:payment_not_paid_out_payment) do + let(:payment_not_paid_out_payment) do entities_yesterday[:charge_paid] end @@ -944,13 +909,13 @@ def generate_donation(h) payment_not_paid_out_payment QueryPayments.full_search(nonprofit.id, {payout_id: payout.id}) end - + before(:each) do bank_account payment_payouts end - it 'sets the correct number of rows' do + it "sets the correct number of rows" do expect(result[:data].count).to eq 4 # the payment header, the four paid out payments end end diff --git a/spec/lib/query/query_recurring_donations_spec.rb b/spec/lib/query/query_recurring_donations_spec.rb index 6c3f7872d..13d6e1ea2 100644 --- a/spec/lib/query/query_recurring_donations_spec.rb +++ b/spec/lib/query/query_recurring_donations_spec.rb @@ -1,333 +1,327 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" # Note that the recurring donation used in these tests is created on 2020-01-01 and the first charge is created on that date describe QueryRecurringDonations do - around(:each) {|example| + around(:each) { |example| Timecop.freeze(2020, 4, 5) do example.run end } - describe '.monthly_total' do - - let(:nonprofit) {Qx.insert_into(:nonprofits).values(name: SecureRandom.uuid).ts.returning('*').execute.first} + describe ".monthly_total" do + let(:nonprofit) { Qx.insert_into(:nonprofits).values(name: SecureRandom.uuid).ts.returning("*").execute.first } let(:rec_dons) do - Qx.insert_into('recurring_donations').values([ - {active: true, amount: 4000, interval: 1, time_unit: 'month'}, - {active: true, amount: 1000, interval: 2, time_unit: 'week'}, - {active: false, amount: 10000, interval: 1, time_unit: 'month'} - ]).common_values({nonprofit_id: nonprofit['id']}).ts.returning("*").execute - end - - it 'adds up the total for all active recurring donations' do - rec_dons - sum = QueryRecurringDonations.monthly_total(nonprofit['id']) - expect(sum).to eq(rec_dons[0]['amount'] + rec_dons[1]['amount']) + Qx.insert_into("recurring_donations").values([ + {active: true, amount: 4000, interval: 1, time_unit: "month"}, + {active: true, amount: 1000, interval: 2, time_unit: "week"}, + {active: false, amount: 10000, interval: 1, time_unit: "month"} + ]).common_values({nonprofit_id: nonprofit["id"]}).ts.returning("*").execute end - end - describe '.is_due?' do + it "adds up the total for all active recurring donations" do + rec_dons + sum = QueryRecurringDonations.monthly_total(nonprofit["id"]) + expect(sum).to eq(rec_dons[0]["amount"] + rec_dons[1]["amount"]) + end + end - let(:nonprofit) {force_create(:nonprofit)} - let(:supporter) {force_create(:supporter, nonprofit: nonprofit)} - let(:donation) { + describe ".is_due?" do + let(:nonprofit) { force_create(:nonprofit) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } + let(:donation) { force_create(:donation, amount: 1000, supporter: supporter, recurring: true, nonprofit: nonprofit) - } - let(:defaults) {{amount: 1000, interval: 1, time_unit: 'month', nonprofit: nonprofit, supporter: supporter, active: true, donation: donation}} + let(:defaults) { {amount: 1000, interval: 1, time_unit: "month", nonprofit: nonprofit, supporter: supporter, active: true, donation: donation} } def create_recdon(params) force_create(:recurring_donation, defaults.merge(params)) end - it 'when inactive, is not due' do + it "when inactive, is not due" do rd = create_recdon(active: false) expect(QueryRecurringDonations.is_due?(rd.id)).to eq(false) end - it 'when it hits max n_failures, is not due' do + it "when it hits max n_failures, is not due" do rd = create_recdon(n_failures: 3) expect(QueryRecurringDonations.is_due?(rd.id)).to eq(false) end - it 'is due when it has no charges' do + it "is due when it has no charges" do rd = create_recdon({}) expect(QueryRecurringDonations.is_due?(rd.id)).to eq(true) end - it 'is not due when it has a charge this month' do + it "is not due when it has a charge this month" do rd = create_recdon({}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end - it 'is due when it has charges && when monthly && not paid this month && not paid last month' do + it "is due when it has charges && when monthly && not paid this month && not paid last month" do rd = create_recdon({}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(2.months.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when monthly && no paydate && last charge was last month && last charge created at day <= today' do + it "is due when monthly && no paydate && last charge was last month && last charge created at day <= today" do rd = create_recdon({}) Timecop.freeze(Time.parse("2020-01-01")) do - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex end Timecop.freeze(Time.parse("2020-02-01")) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when monthly && paydate present && last charge was last month && paydate <= today' do + it "is due when monthly && paydate present && last charge was last month && paydate <= today" do rd = create_recdon({paydate: 10}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(1.month.from_now.change(day: 10)) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when not monthly and the timespan is 3 days and it is 3 days later' do - rd = create_recdon({time_unit: 'day', interval: 3}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + it "is due when not monthly and the timespan is 3 days and it is 3 days later" do + rd = create_recdon({time_unit: "day", interval: 3}) + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(3.days.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when not monthly and the timespan is 2 weeks and it is 2 weeks later' do - rd = create_recdon({time_unit: 'week', interval: 2}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + it "is due when not monthly and the timespan is 2 weeks and it is 2 weeks later" do + rd = create_recdon({time_unit: "week", interval: 2}) + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(2.weeks.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when not monthly and the timespan is 1 year and it is 1 year later' do - rd = create_recdon({time_unit: 'year', interval: 1}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + it "is due when not monthly and the timespan is 1 year and it is 1 year later" do + rd = create_recdon({time_unit: "year", interval: 1}) + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(1.year.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is not due when not monthly and it is not a timespan later' do - rd = create_recdon({time_unit: 'day', interval: 3}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + it "is not due when not monthly and it is not a timespan later" do + rd = create_recdon({time_unit: "day", interval: 3}) + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(2.days.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end end - it 'is not due when monthly and has been paid this month' do + it "is not due when monthly and has been paid this month" do rd = create_recdon({}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end - it 'is not due when monthly and no paydate and today is < last charge created_at day' do + it "is not due when monthly and no paydate and today is < last charge created_at day" do rd = create_recdon({}) Timecop.freeze(Time.parse("2020-01-02")) do - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex end Timecop.freeze(Time.parse("2020-02-01")) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end end - it 'is not due when monthly an a paydate is present and today < paydate' do + it "is not due when monthly an a paydate is present and today < paydate" do rd = create_recdon({paydate: 2}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'pending').ts.ex + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "pending").ts.ex Timecop.freeze(1.month.from_now.change(day: 1)) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end end - it 'is due when monthly and there are only failed charges this month' do + it "is due when monthly and there are only failed charges this month" do rd = create_recdon({}) - Qx.insert_into(:charges).values(donation_id: rd['donation_id'], amount: 1000, supporter_id: supporter['id'], nonprofit_id: nonprofit['id'], status: 'failed').ts.ex + Qx.insert_into(:charges).values(donation_id: rd["donation_id"], amount: 1000, supporter_id: supporter["id"], nonprofit_id: nonprofit["id"], status: "failed").ts.ex Timecop.freeze(1.month.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when monthly AND there is a recurring_donation_hold but no end_date' do + it "is due when monthly AND there is a recurring_donation_hold but no end_date" do rd = create_recdon({}) rd.create_recurring_donation_hold! Timecop.freeze(1.month.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when monthly AND there is a recurring_donation_hold but end_date has passed' do + it "is due when monthly AND there is a recurring_donation_hold but end_date has passed" do rd = create_recdon({}) rd.create_recurring_donation_hold end_date: 1.week.from_now Timecop.freeze(1.month.from_now) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is due when monthly AND there is a recurring_donation_hold and end_date has passed but were still in the current month' do + it "is due when monthly AND there is a recurring_donation_hold and end_date has passed but were still in the current month" do rd = create_recdon({}) rd.create_recurring_donation_hold end_date: 1.month.from_now + 1.day Timecop.freeze(1.month.from_now + 2.days) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is not due when monthly AND there is a recurring_donation_hold and end_date hasnt passed' do + it "is not due when monthly AND there is a recurring_donation_hold and end_date hasnt passed" do rd = create_recdon({}) rd.create_recurring_donation_hold end_date: 1.week.from_now - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end - it 'is not due when monthly AND the recurring_donation_hold has just ended' do + it "is not due when monthly AND the recurring_donation_hold has just ended" do donation = force_create(:donation) payment = force_create(:payment, donation: donation) - last_charge = force_create(:charge, payment: payment, status: 'disbursed', donation: donation, created_at: Time.new(2021,1,15)) - rd = create_recdon({ donation: donation }) - Timecop.freeze(Time.new(2021,5,2)) do - rd.create_recurring_donation_hold end_date: Time.new(2021,5,1) - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + force_create(:charge, payment: payment, status: "disbursed", donation: donation, created_at: Time.new(2021, 1, 15)) + rd = create_recdon({donation: donation}) + Timecop.freeze(Time.new(2021, 5, 2)) do + rd.create_recurring_donation_hold end_date: Time.new(2021, 5, 1) + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end end - it 'is not due when monthly AND the recurring_donation_hold has just ended AND paydate specifically is in the future' do + it "is not due when monthly AND the recurring_donation_hold has just ended AND paydate specifically is in the future" do donation = force_create(:donation) payment = force_create(:payment, donation: donation) - last_charge = force_create(:charge, payment: payment, status: 'disbursed', donation: donation, created_at: Time.new(2021,1,15)) - rd = create_recdon({ donation: donation, paydate: 22 }) - rd.create_recurring_donation_hold end_date: Time.new(2021,5,1) - Timecop.freeze(Time.new(2021,5,1)) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + force_create(:charge, payment: payment, status: "disbursed", donation: donation, created_at: Time.new(2021, 1, 15)) + rd = create_recdon({donation: donation, paydate: 22}) + rd.create_recurring_donation_hold end_date: Time.new(2021, 5, 1) + Timecop.freeze(Time.new(2021, 5, 1)) do + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end - Timecop.freeze(Time.new(2021,5,2)) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + Timecop.freeze(Time.new(2021, 5, 2)) do + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end end - it 'is due when monthly AND the recurring_donation_hold has just ended AND has paydate and is time to charge!' do + it "is due when monthly AND the recurring_donation_hold has just ended AND has paydate and is time to charge!" do donation = force_create(:donation) payment = force_create(:payment, donation: donation) - last_charge = force_create(:charge, payment: payment, status: 'disbursed', donation: donation, created_at: Time.new(2021,1,15)) - rd = create_recdon({ donation: donation, paydate: 22 }) - rd.create_recurring_donation_hold end_date: Time.new(2021,5,1) - Timecop.freeze(Time.new(2021,5,22)) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be true + force_create(:charge, payment: payment, status: "disbursed", donation: donation, created_at: Time.new(2021, 1, 15)) + rd = create_recdon({donation: donation, paydate: 22}) + rd.create_recurring_donation_hold end_date: Time.new(2021, 5, 1) + Timecop.freeze(Time.new(2021, 5, 22)) do + expect(QueryRecurringDonations.is_due?(rd["id"])).to be true end end - it 'is not due when monthly AND the recurring_donation_hold has just ended AND has paydate and is almost time to charge' do + it "is not due when monthly AND the recurring_donation_hold has just ended AND has paydate and is almost time to charge" do donation = force_create(:donation) payment = force_create(:payment, donation: donation) - last_charge = force_create(:charge, payment: payment, status: 'disbursed', donation: donation, created_at: Time.new(2021,1,15)) - rd = create_recdon({ donation: donation, paydate: 22 }) - rd.create_recurring_donation_hold end_date: Time.new(2021,5,1) - Timecop.freeze(Time.new(2021,5,21)) do - expect(QueryRecurringDonations.is_due?(rd['id'])).to be false + force_create(:charge, payment: payment, status: "disbursed", donation: donation, created_at: Time.new(2021, 1, 15)) + rd = create_recdon({donation: donation, paydate: 22}) + rd.create_recurring_donation_hold end_date: Time.new(2021, 5, 1) + Timecop.freeze(Time.new(2021, 5, 21)) do + expect(QueryRecurringDonations.is_due?(rd["id"])).to be false end end end - describe '.for_export_enumerable' do + describe ".for_export_enumerable" do around(:each) do |ex| StripeMockHelper.mock do ex.run end end - - let(:failed) {[ - force_create(:recurring_donation, amount: 2000, active: true, n_failures: 3, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_2"), - force_create(:recurring_donation, amount: 400, active: false, n_failures: 3, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_4") - ]} + let(:failed) { + [ + force_create(:recurring_donation, amount: 2000, active: true, n_failures: 3, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_2"), + force_create(:recurring_donation, amount: 400, active: false, n_failures: 3, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_4") + ] + } let(:cancelled) { - [force_create(:recurring_donation, amount: 1000, active: false, n_failures: 0, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_1"), - - ] - } + [force_create(:recurring_donation, amount: 1000, active: false, n_failures: 0, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_1")] + } - let(:active) { [ - force_create(:recurring_donation, amount: 3000, active: true, n_failures: 0, nonprofit: @nonprofit, donation: force_create(:donation, card: force_create(:card, stripe_customer_id: "stripe_cus_id")), edit_token: "edit_token_3"), - force_create(:recurring_donation, amount: 200, active: true, n_failures: 0, end_date: Time.current + 1.day, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_6") - ]} + let(:active) { + [ + force_create(:recurring_donation, amount: 3000, active: true, n_failures: 0, nonprofit: @nonprofit, donation: force_create(:donation, card: force_create(:card, stripe_customer_id: "stripe_cus_id")), edit_token: "edit_token_3"), + force_create(:recurring_donation, amount: 200, active: true, n_failures: 0, end_date: 1.day.from_now, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_6") + ] + } - let(:fulfilled) {[ - force_create(:recurring_donation, amount: 100, active: true, n_failures: 0, end_date: Time.current - 1.day, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_5"), - ]} + let(:fulfilled) { + [ + force_create(:recurring_donation, amount: 100, active: true, n_failures: 0, end_date: 1.day.ago, nonprofit: @nonprofit, donation: force_create(:donation), edit_token: "edit_token_5") + ] + } before :each do - @nonprofit = force_create(:nonprofit, name: "npo1"); - @supporters = [ force_create(:supporter, name: "supporter-0", nonprofit: @nonprofit), - force_create(:supporter, name: "supporter-1", nonprofit: @nonprofit)] - - + @nonprofit = force_create(:nonprofit, name: "npo1") + @supporters = [force_create(:supporter, name: "supporter-0", nonprofit: @nonprofit), + force_create(:supporter, name: "supporter-1", nonprofit: @nonprofit)] @recurring_donations = [].concat(failed).concat(cancelled).concat(active).concat(fulfilled) - @root_url ='https://localhost:8080' + @root_url = "https://localhost:8080" end - let(:headers) { MockHelpers.recurring_donation_export_headers} + let(:headers) { MockHelpers.recurring_donation_export_headers } - it 'finishes recurring donation export' do - rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {}).to_a), headers: true) + it "finishes recurring donation export" do + rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {}).to_a), headers: true) expect(rows.length).to eq(6) expect(rows[0].headers).to eq(headers) - end - it 'retrieves active' do - rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {:active_and_not_failed => true, :root_url => 'https://localhost:8080/'}).to_a), headers: true) + it "retrieves active" do + rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {active_and_not_failed: true, root_url: "https://localhost:8080/"}).to_a), headers: true) expect(rows.length).to eq(2) expect(rows[0].headers).to eq(headers) expect(rows[0]["Amount"]).to eq("$30.00") expect(rows[0]["Status"]).to eq "active" expect(rows[1]["Amount"]).to eq("$2.00") - expect(rows[0]["Donation Management Url"]).to eq(MockHelpers.generate_expected_rd_management_url(@root_url,active[0])) + expect(rows[0]["Donation Management Url"]).to eq(MockHelpers.generate_expected_rd_management_url(@root_url, active[0])) expect(rows[0]["Status"]).to eq "active" end - it 'retrieves fulfilled' do - rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {:fulfilled => true, :root_url => 'https://localhost:8080/'}).to_a), headers: true) - + it "retrieves fulfilled" do + rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {fulfilled: true, root_url: "https://localhost:8080/"}).to_a), headers: true) expect(rows.length).to eq(1) expect(rows[0].headers).to eq(headers) expect(rows[0]["Amount"]).to eq("$1.00") expect(rows[0]["Status"]).to eq "fulfilled" - expect(rows[0]["Donation Management Url"]).to eq('') - + expect(rows[0]["Donation Management Url"]).to eq("") end - it 'retrieves cancelled' do - rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {:active_and_not_failed => false, :root_url => 'https://localhost:8080/'}).to_a), headers: true) + it "retrieves cancelled" do + rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {active_and_not_failed: false, root_url: "https://localhost:8080/"}).to_a), headers: true) expect(rows.length).to eq(1) expect(rows[0].headers).to eq(headers) expect(rows[0]["Amount"]).to eq("$10.00") - expect(rows[0]["Donation Management Url"]).to eq('') + expect(rows[0]["Donation Management Url"]).to eq("") expect(rows[0]["Status"]).to eq "cancelled" end - context 'failed charges' do - it 'retrieves failed' do - rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {:failed => true, :root_url => 'https://localhost:8080/'}).to_a), headers: true) + context "failed charges" do + it "retrieves failed" do + rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {failed: true, root_url: "https://localhost:8080/"}).to_a), headers: true) expect(rows.length).to eq(1) expect(rows[0].headers).to eq(headers) expect(rows[0]["Amount"]).to eq("$20.00") expect(rows[0]["Donation Management Url"]).to eq(MockHelpers.generate_expected_rd_management_url(@root_url, failed[0])) - end - context 'when the query includes last failed charge param' do + context "when the query includes last failed charge param" do before do end let(:headers_with_last_failed_charge) do @@ -337,12 +331,12 @@ def create_recdon(params) let(:rows) do CSV.parse( Format::Csv.from_array( - QueryRecurringDonations::for_export_enumerable( + QueryRecurringDonations.for_export_enumerable( @nonprofit.id, { - :failed => true, - :include_last_failed_charge => true, - :root_url => 'https://localhost:8080/' + failed: true, + include_last_failed_charge: true, + root_url: "https://localhost:8080/" } ).to_a ), @@ -350,30 +344,29 @@ def create_recdon(params) ) end - it 'contains Last Failed Charge' do + it "contains Last Failed Charge" do expect(rows[0].headers).to eq(headers_with_last_failed_charge) end end end - it 'retrieves not-failed' do - rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {:failed => false, :root_url => 'https://localhost:8080/'}).to_a), headers: true) + it "retrieves not-failed" do + rows = CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {failed: false, root_url: "https://localhost:8080/"}).to_a), headers: true) expect(rows.length).to eq(4) expect(rows[0].headers).to eq(headers) expect(rows[0]["Amount"]).to eq("$10.00") expect(rows[1]["Amount"]).to eq("$30.00") - expect(rows[3]["Donation Management Url"]).to eq('') + expect(rows[3]["Donation Management Url"]).to eq("") end - it 'gets the stripe_customer_id when requested' do - expect(csv.select{|i| i['Stripe Customer Id'] == 'stripe_cus_id'}).to be_any + it "gets the stripe_customer_id when requested" do + expect(csv.select { |i| i["Stripe Customer Id"] == "stripe_cus_id" }).to be_any end let(:csv) do - CSV.parse(Format::Csv.from_array(QueryRecurringDonations::for_export_enumerable(@nonprofit.id, {:active_and_not_failed => true, include_stripe_customer_id: true, :root_url => 'https://localhost:8080/'}).to_a), headers: true) + CSV.parse(Format::Csv.from_array(QueryRecurringDonations.for_export_enumerable(@nonprofit.id, {active_and_not_failed: true, include_stripe_customer_id: true, root_url: "https://localhost:8080/"}).to_a), headers: true) end - end end # describe diff --git a/spec/lib/query/query_roles_spec.rb b/spec/lib/query/query_roles_spec.rb index 18aa6a9a8..cf1bde309 100644 --- a/spec/lib/query/query_roles_spec.rb +++ b/spec/lib/query/query_roles_spec.rb @@ -1,37 +1,36 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QueryRoles do include_context :shared_donation_charge_context - let(:nonprofit_admin_role) {force_create(:role, user: user, host: nonprofit, name: :nonprofit_admin)} - let(:other_nonprofit_admin_role) {force_create(:role, user: user, host: other_nonprofit, name: :nonprofit_admin)} - let(:nonprofit_associate_role) {force_create(:role, user: user, host: nonprofit, name: :nonprofit_associate)} - let(:other_nonprofit_associate_role) {force_create(:role, user: user, host: other_nonprofit, name: :nonprofit_associate)} + let(:nonprofit_admin_role) { force_create(:role, user: user, host: nonprofit, name: :nonprofit_admin) } + let(:other_nonprofit_admin_role) { force_create(:role, user: user, host: other_nonprofit, name: :nonprofit_admin) } + let(:nonprofit_associate_role) { force_create(:role, user: user, host: nonprofit, name: :nonprofit_associate) } + let(:other_nonprofit_associate_role) { force_create(:role, user: user, host: other_nonprofit, name: :nonprofit_associate) } - describe 'is_nonprofit_user?' do - it 'false for no role' do + describe "is_nonprofit_user?" do + it "false for no role" do expect(QueryRoles.is_nonprofit_user?(user.id, nonprofit.id)).to be_falsey end - it 'false for other nonprofit admin' do + it "false for other nonprofit admin" do other_nonprofit_admin_role expect(QueryRoles.is_nonprofit_user?(user.id, nonprofit.id)).to be_falsey end - it 'false for other nonprofit associate' do + it "false for other nonprofit associate" do other_nonprofit_associate_role expect(QueryRoles.is_nonprofit_user?(user.id, nonprofit.id)).to be_falsey end - it 'true for nonprofit admin' do + it "true for nonprofit admin" do nonprofit_admin_role expect(QueryRoles.is_nonprofit_user?(user.id, nonprofit.id)).to be_truthy end - it 'true for nonprofit admin' do + it "true for nonprofit admin" do nonprofit_associate_role expect(QueryRoles.is_nonprofit_user?(user.id, nonprofit.id)).to be_truthy end end - -end \ No newline at end of file +end diff --git a/spec/lib/query/query_source_token_spec.rb b/spec/lib/query/query_source_token_spec.rb index 3c36ba7b9..0b055b28d 100644 --- a/spec/lib/query/query_source_token_spec.rb +++ b/spec/lib/query/query_source_token_spec.rb @@ -1,28 +1,29 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QuerySourceToken do - describe '.get_and_increment_source_token' do - let(:our_uuid) {'7ab66a26-05e5-11e8-b4ef-8f19083c3cc7'} #random uuid I generated - let(:not_our_uuid) {'a96e3c2c-05e5-11e8-80cc-177b86bb74cd'} # ditto - let(:fake_uuid) {'15c13da0-05e8-11e8-9cc0-e7ccb95e5f1f'} #ditto - let(:expired_uuid) {'061124ca-05f1-11e8-8730-57558ad1064d'} - let(:overused_uuid) {'0ac67006-05f1-11e8-902c-035df51dbc79'} - - let(:nonprofit) {force_create(:nonprofit)} - let(:event) {force_create(:event, nonprofit: nonprofit)} - let(:user) {u = force_create(:user) - force_create(:role, name: :nonprofit_admin, host: nonprofit, user: u) - u + describe ".get_and_increment_source_token" do + let(:our_uuid) { "7ab66a26-05e5-11e8-b4ef-8f19083c3cc7" } # random uuid I generated + let(:not_our_uuid) { "a96e3c2c-05e5-11e8-80cc-177b86bb74cd" } # ditto + let(:fake_uuid) { "15c13da0-05e8-11e8-9cc0-e7ccb95e5f1f" } # ditto + let(:expired_uuid) { "061124ca-05f1-11e8-8730-57558ad1064d" } + let(:overused_uuid) { "0ac67006-05f1-11e8-902c-035df51dbc79" } + + let(:nonprofit) { force_create(:nonprofit) } + let(:event) { force_create(:event, nonprofit: nonprofit) } + let(:user) { + u = force_create(:user) + force_create(:role, name: :nonprofit_admin, host: nonprofit, user: u) + u } - let(:other_user) {force_create(:user)} + let(:other_user) { force_create(:user) } - let(:our_source_token) {force_create(:source_token, token: our_uuid, total_uses: 0, expiration: Time.now + 1.day, max_uses: 1, event:event)} - let(:not_our_source_token) {force_create(:source_token, token: not_our_uuid, total_uses: 0, expiration: Time.now + 1.day, max_uses: 1)} + let(:our_source_token) { force_create(:source_token, token: our_uuid, total_uses: 0, expiration: Time.now + 1.day, max_uses: 1, event: event) } + let(:not_our_source_token) { force_create(:source_token, token: not_our_uuid, total_uses: 0, expiration: Time.now + 1.day, max_uses: 1) } - let(:expired_source_token) {force_create(:source_token, token: expired_uuid, total_uses: 0, expiration: Time.now - 1.day) } - let(:overused_source_token) {force_create(:source_token, token: overused_uuid, total_uses: 1, expiration: Time.now + 1.day, max_uses: 1) } + let(:expired_source_token) { force_create(:source_token, token: expired_uuid, total_uses: 0, expiration: Time.now - 1.day) } + let(:overused_source_token) { force_create(:source_token, token: overused_uuid, total_uses: 1, expiration: Time.now + 1.day, max_uses: 1) } before(:each) { our_source_token @@ -31,73 +32,72 @@ overused_source_token } - around(:each) {|example| + around(:each) { |example| Timecop.freeze(2020, 5, 4) do example.run end - } - describe 'param validation' do - it 'basic validation' do - expect { QuerySourceToken.get_and_increment_source_token(nil) }.to raise_error {|error| + describe "param validation" do + it "basic validation" do + expect { QuerySourceToken.get_and_increment_source_token(nil) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {key: :token, name: :required}, - {key: :token, name: :format} + {key: :token, name: :required}, + {key: :token, name: :format} ]) } end - it 'raises if source_token cant be found' do - expect { QuerySourceToken.get_and_increment_source_token(fake_uuid) }.to raise_error {|error| + it "raises if source_token cant be found" do + expect { QuerySourceToken.get_and_increment_source_token(fake_uuid) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {key: :token} + {key: :token} ]) expect(error.message).to eq "#{fake_uuid} doesn't represent a valid source" } end - it 'raises if token already used too much' do - expect{ QuerySourceToken.get_and_increment_source_token(overused_uuid) }.to raise_error {|error| + it "raises if token already used too much" do + expect { QuerySourceToken.get_and_increment_source_token(overused_uuid) }.to raise_error { |error| expect(error).to be_a ExpiredTokenError } end - it 'raises if token expired' do - expect{ QuerySourceToken.get_and_increment_source_token(expired_uuid) }.to raise_error {|error| + it "raises if token expired" do + expect { QuerySourceToken.get_and_increment_source_token(expired_uuid) }.to raise_error { |error| expect(error).to be_a ExpiredTokenError } end - it 'raises authentication error if event on it but user is nil' do - expect { QuerySourceToken.get_and_increment_source_token(our_uuid) }.to raise_error {|error| + it "raises authentication error if event on it but user is nil" do + expect { QuerySourceToken.get_and_increment_source_token(our_uuid) }.to raise_error { |error| expect(error).to be_a AuthenticationError } end - it 'raises authentication error if event on it but user is not with nonprofit' do - expect { QuerySourceToken.get_and_increment_source_token(our_uuid, other_user) }.to raise_error {|error| + it "raises authentication error if event on it but user is not with nonprofit" do + expect { QuerySourceToken.get_and_increment_source_token(our_uuid, other_user) }.to raise_error { |error| expect(error).to be_a AuthenticationError } end end - it 'increments and returns source token' do + it "increments and returns source token" do result = QuerySourceToken.get_and_increment_source_token(our_uuid, user) expect(result).to be_a SourceToken expected = { - total_uses: 1, - max_uses: 1, - created_at: Time.now, - updated_at: Time.now, - event_id: event.id, - expiration: Time.now + 1.day, - token: our_uuid, - tokenizable_id: nil, - tokenizable_type: nil + total_uses: 1, + max_uses: 1, + created_at: Time.now, + updated_at: Time.now, + event_id: event.id, + expiration: Time.now + 1.day, + token: our_uuid, + tokenizable_id: nil, + tokenizable_type: nil }.with_indifferent_access expect(result.attributes).to eq expected @@ -113,4 +113,4 @@ def reload_all_tokens overused_source_token.reload end end -end \ No newline at end of file +end diff --git a/spec/lib/query/query_supporters_spec.rb b/spec/lib/query/query_supporters_spec.rb index a63b4657a..026850aea 100644 --- a/spec/lib/query/query_supporters_spec.rb +++ b/spec/lib/query/query_supporters_spec.rb @@ -1,38 +1,36 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QuerySupporters do - let(:gift_level_one_time) { 1111 } let(:gift_level_recurring) { 5585 } - let(:gift_level_changed_recurring) {5512 } + let(:gift_level_changed_recurring) { 5512 } let(:campaign_gift_option_name) { "theowthoinv" } - - let(:np) { force_create(:nonprofit)} - let(:supporter1) { force_create(:supporter, nonprofit: np, name: 'Cacau')} - let(:supporter2) { force_create(:supporter, nonprofit: np, name: 'Penelope')} - let(:campaign) { force_create(:campaign, nonprofit: np, slug: "slug stuff")} - let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, name: campaign_gift_option_name, amount_one_time: gift_level_one_time, amount_recurring: gift_level_recurring)} - let(:campaign_gift1) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation1)} + let(:np) { force_create(:nonprofit) } + let(:supporter1) { force_create(:supporter, nonprofit: np, name: "Cacau") } + let(:supporter2) { force_create(:supporter, nonprofit: np, name: "Penelope") } + let(:campaign) { force_create(:campaign, nonprofit: np, slug: "slug stuff") } + let(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign, name: campaign_gift_option_name, amount_one_time: gift_level_one_time, amount_recurring: gift_level_recurring) } + let(:campaign_gift1) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation1) } let(:payment_utc_time) { Time.new(2021, 10, 10, 1, 1, 0, "+00:00") } let(:payment2_utc_time) { Time.new(2021, 1, 1, 1, 1, 0, "+00:00") } - let(:donation1) { force_create(:donation, amount: gift_level_one_time, campaign: campaign, supporter:supporter1, date: payment_utc_time)} - let(:donation4) { force_create(:donation, amount: gift_level_one_time, campaign: campaign, supporter:supporter1, date: payment2_utc_time)} - let(:donation5) { force_create(:donation, amount: gift_level_one_time, campaign: campaign, supporter:supporter2, date: payment2_utc_time)} + let(:donation1) { force_create(:donation, amount: gift_level_one_time, campaign: campaign, supporter: supporter1, date: payment_utc_time) } + let(:donation4) { force_create(:donation, amount: gift_level_one_time, campaign: campaign, supporter: supporter1, date: payment2_utc_time) } + let(:donation5) { force_create(:donation, amount: gift_level_one_time, campaign: campaign, supporter: supporter2, date: payment2_utc_time) } - let(:payment1) {force_create(:payment, gross_amount: gift_level_one_time, donation: donation1, date: payment_utc_time, nonprofit: np)} + let(:payment1) { force_create(:payment, gross_amount: gift_level_one_time, donation: donation1, date: payment_utc_time, nonprofit: np) } - let(:donation2) {force_create(:donation, amount: gift_level_changed_recurring, campaign: campaign, supporter:supporter2)} - let(:payment2) {force_create(:payment, gross_amount: gift_level_recurring, donation: donation2, nonprofit: np)} - let(:payment4) {force_create(:payment, gross_amount: gift_level_one_time, donation: donation4, date: payment2_utc_time, nonprofit: np)} - let(:payment5) {force_create(:payment, gross_amount: gift_level_one_time, donation: donation5, date: payment2_utc_time, nonprofit: np)} + let(:donation2) { force_create(:donation, amount: gift_level_changed_recurring, campaign: campaign, supporter: supporter2) } + let(:payment2) { force_create(:payment, gross_amount: gift_level_recurring, donation: donation2, nonprofit: np) } + let(:payment4) { force_create(:payment, gross_amount: gift_level_one_time, donation: donation4, date: payment2_utc_time, nonprofit: np) } + let(:payment5) { force_create(:payment, gross_amount: gift_level_one_time, donation: donation5, date: payment2_utc_time, nonprofit: np) } - let(:payment3) {force_create(:payment, gross_amount: gift_level_changed_recurring, donation: donation2)} - let(:campaign_gift2) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation2)} - let(:recurring) {force_create(:recurring_donation, donation: donation2, amount: gift_level_changed_recurring)} + let(:payment3) { force_create(:payment, gross_amount: gift_level_changed_recurring, donation: donation2) } + let(:campaign_gift2) { force_create(:campaign_gift, campaign_gift_option: campaign_gift_option, donation: donation2) } + let(:recurring) { force_create(:recurring_donation, donation: donation2, amount: gift_level_changed_recurring) } let(:note_content_1) do "CONTENT1" @@ -47,15 +45,15 @@ end let(:supporter_note_for_s1) do - force_create(:supporter_note, supporter: supporter1, created_at: DateTime.new(2018,1,5), content: note_content_1) + force_create(:supporter_note, supporter: supporter1, created_at: DateTime.new(2018, 1, 5), content: note_content_1) end let(:supporter_note_1_for_s2) do - force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2018,2,5), content: note_content_2) + force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2018, 2, 5), content: note_content_2) end let(:supporter_note_2_for_s2) do - force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2020,4, 5), content: note_content_3) + force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2020, 4, 5), content: note_content_3) end let(:note_content_1) do @@ -71,18 +69,17 @@ end let(:supporter_note_for_s1) do - force_create(:supporter_note, supporter: supporter1, created_at: DateTime.new(2018,1,5), content: note_content_1) + force_create(:supporter_note, supporter: supporter1, created_at: DateTime.new(2018, 1, 5), content: note_content_1) end let(:supporter_note_1_for_s2) do - force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2018,2,5), content: note_content_2) + force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2018, 2, 5), content: note_content_2) end let(:supporter_note_2_for_s2) do - force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2020,4, 5), content: note_content_3) + force_create(:supporter_note, supporter: supporter2, created_at: DateTime.new(2020, 4, 5), content: note_content_3) end - let(:init_all) { np supporter1 @@ -96,21 +93,19 @@ } let(:campaign_list) { - QuerySupporters.campaign_list(np.id, campaign.id, {page: 0}) } - it 'counts gift donations properly' do + it "counts gift donations properly" do init_all glm = campaign_list data = glm[:data] - expect(data.map{|i| i['total_raised']}).to match_array([gift_level_one_time, gift_level_recurring]) - + expect(data.map { |i| i["total_raised"] }).to match_array([gift_level_one_time, gift_level_recurring]) end - describe '.supporter_note_export_enumerable' do + describe ".supporter_note_export_enumerable" do let(:lazy_enumerable) do supporter_note_for_s1 supporter_note_1_for_s2 @@ -118,23 +113,22 @@ QuerySupporters.supporter_note_export_enumerable(np.id, {}) end - it 'is a lazy enumerable' do + it "is a lazy enumerable" do expect(lazy_enumerable).to be_a Enumerator::Lazy end - it 'is three items long' do - expect(lazy_enumerable.to_a.count).to eq 4 + it "is three items long" do + expect(lazy_enumerable.to_a.size).to eq 4 end - it 'has correct headers' do - expect(lazy_enumerable.to_a.first).to eq ['Id', 'Email', 'Note Created At', 'Note Contents'] + it "has correct headers" do + expect(lazy_enumerable.to_a.first).to eq ["Id", "Email", "Note Created At", "Note Contents"] end end - describe '.full_search' do - - let(:tag_master1) { create(:tag_master_base, nonprofit: supporter1.nonprofit)} - let(:tag_master2) { create(:tag_master_base, nonprofit: supporter1.nonprofit)} + describe ".full_search" do + let(:tag_master1) { create(:tag_master_base, nonprofit: supporter1.nonprofit) } + let(:tag_master2) { create(:tag_master_base, nonprofit: supporter1.nonprofit) } before do supporter1.payments = [payment1, payment4] supporter2.payments = [payment5] @@ -142,195 +136,193 @@ supporter1.tag_joins.create(tag_master: tag_master1) supporter1.tag_joins.create(tag_master: tag_master2) end - it 'returns the UTC date when the timezone is not specified' do - result = QuerySupporters.full_search(np.id, { search: 'Cacau' }) - expect(result[:data].first["last_contribution"]).to eq(payment_utc_time.strftime('%m/%d/%y')) + it "returns the UTC date when the timezone is not specified" do + result = QuerySupporters.full_search(np.id, {search: "Cacau"}) + expect(result[:data].first["last_contribution"]).to eq(payment_utc_time.strftime("%m/%d/%y")) end - it 'returns the converted date when the timezone is specified' do - np.update_attributes(timezone: 'America/New_York') - result = QuerySupporters.full_search(np.id, { search: 'Cacau' }) - expect(result[:data].first["last_contribution"]).to eq((payment_utc_time - 1.day).strftime('%m/%d/%y')) + it "returns the converted date when the timezone is specified" do + np.update_attributes(timezone: "America/New_York") + result = QuerySupporters.full_search(np.id, {search: "Cacau"}) + expect(result[:data].first["last_contribution"]).to eq((payment_utc_time - 1.day).strftime("%m/%d/%y")) end - it 'finds the payments on dates after the specified dates' do - np.update_attributes(timezone: 'America/New_York') - result = QuerySupporters.full_search(np.id, { last_payment_after: (payment2_utc_time + 1.day).to_s }) + it "finds the payments on dates after the specified dates" do + np.update_attributes(timezone: "America/New_York") + result = QuerySupporters.full_search(np.id, {last_payment_after: (payment2_utc_time + 1.day).to_s}) expect(result[:data].count).to eq 1 end - it 'finds the payments on dates before the specified dates' do - np.update_attributes(timezone: 'America/New_York') - result = QuerySupporters.full_search(np.id, { last_payment_before: payment_utc_time.to_s }) + it "finds the payments on dates before the specified dates" do + np.update_attributes(timezone: "America/New_York") + result = QuerySupporters.full_search(np.id, {last_payment_before: payment_utc_time.to_s}) expect(result[:data].count).to eq 2 end - it 'includes tags as an array on supporter with tags' do + it "includes tags as an array on supporter with tags" do result = QuerySupporters.full_search(np.id, {}) expect(result[:data][0]["tags"]).to be_a Array - end - it 'includes tags as null on supporter without a tag' do + it "includes tags as null on supporter without a tag" do result = QuerySupporters.full_search(np.id, {}) expect(result[:data][1]["tags"]).to eq nil - end context 'when searching by "at least" contributed' do - it 'finds the supporter who raised exactly what was being looked for' do - result = QuerySupporters.full_search(np.id, { total_raised_greater_than_or_equal: "22.22"}) + it "finds the supporter who raised exactly what was being looked for" do + result = QuerySupporters.full_search(np.id, {total_raised_greater_than_or_equal: "22.22"}) expect(result[:data].count).to eq 1 end it "finds the supporter who raised $22.22 when they enter characters other than a number and a period" do - result = QuerySupporters.full_search(np.id, { total_raised_greater_than_or_equal: "$22,.22"}) + result = QuerySupporters.full_search(np.id, {total_raised_greater_than_or_equal: "$22,.22"}) expect(result[:data].count).to eq 1 end end context 'when searching by "less than" contributed' do - it 'finds the supporter who raised exactly what was being looked for' do - result = QuerySupporters.full_search(np.id, { total_raised_less_than: "22.22"}) + it "finds the supporter who raised exactly what was being looked for" do + result = QuerySupporters.full_search(np.id, {total_raised_less_than: "22.22"}) expect(result[:data].count).to eq 1 end it "finds the supporter who raised $22.22 when they enter characters other than a number and a period" do - result = QuerySupporters.full_search(np.id, { total_raised_less_than: "$22,.22"}) + result = QuerySupporters.full_search(np.id, {total_raised_less_than: "$22,.22"}) expect(result[:data].count).to eq 1 end end - context 'when looking for a phone number' do + context "when looking for a phone number" do before(:each) { supporter1.phone = "+1 (920) 915-4980" supporter1.save! } - it 'finds when using character filled phone number' do - result = QuerySupporters.full_search(np.id, { search: "+1(920) 915*4980a" }) - expect(result[:data][0]['id']).to eq supporter1.id + it "finds when using character filled phone number" do + result = QuerySupporters.full_search(np.id, {search: "+1(920) 915*4980a"}) + expect(result[:data][0]["id"]).to eq supporter1.id end - it 'finds when using spaced phone number' do - result = QuerySupporters.full_search(np.id, { search: "1 920 915 4980" }) - expect(result[:data][0]['id']).to eq supporter1.id + it "finds when using spaced phone number" do + result = QuerySupporters.full_search(np.id, {search: "1 920 915 4980"}) + expect(result[:data][0]["id"]).to eq supporter1.id end - it 'finds when using nonspaced phone number' do - result = QuerySupporters.full_search(np.id, { search: "19209154980" }) - expect(result[:data][0]['id']).to eq supporter1.id + it "finds when using nonspaced phone number" do + result = QuerySupporters.full_search(np.id, {search: "19209154980"}) + expect(result[:data][0]["id"]).to eq supporter1.id end - it 'does not find based on partial phone number' do - result = QuerySupporters.full_search(np.id, { search: "9209154980" }) + it "does not find based on partial phone number" do + result = QuerySupporters.full_search(np.id, {search: "9209154980"}) expect(result[:data].count).to eq 0 # just the headers end end - context 'when looking for a blank phone number' do + context "when looking for a blank phone number" do before(:each) { supporter1.phone = " " supporter1.save! } - it 'finds when using character filled phone number' do - result = QuerySupporters.full_search(np.id, { search: "A search term" }) + it "finds when using character filled phone number" do + result = QuerySupporters.full_search(np.id, {search: "A search term"}) expect(result[:data].count).to eq 0 end end - context 'when filtering by campaign' do + context "when filtering by campaign" do it "finds one supporter" do donation1 donation4 # this is the second for one of the supporters. This verifies we only get a single supporter no matter how many donations they have - result = QuerySupporters.full_search(np.id, { campaign_id: campaign.id.to_s}) + result = QuerySupporters.full_search(np.id, {campaign_id: campaign.id.to_s}) expect(result[:data].count).to eq 2 end end end - describe '.dupes_on_name_and_phone' do + describe ".dupes_on_name_and_phone" do subject { QuerySupporters.dupes_on_name_and_phone(np.id) } - it 'finds supporters with the same name and phone' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '(123) 456-7890') + it "finds supporters with the same name and phone" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "(123) 456-7890") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when different names' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '(123) 456-7890') + context "when different names" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "(123) 456-7890") expect(subject).to match_array([]) end end - context 'when different phones' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567891') + context "when different phones" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567891") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: '', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: '', phone: '(123) 456-7890') + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "", phone: "1234567890") + force_create(:supporter, nonprofit_id: np.id, name: "", phone: "(123) 456-7890") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: nil, phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: nil, phone: '(123) 456-7890') + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: nil, phone: "1234567890") + force_create(:supporter, nonprofit_id: np.id, name: nil, phone: "(123) 456-7890") expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_name_and_phone(np.id, false) } - context 'when names are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'CACAU', phone: '(123)4567890') + context "when names are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau", phone: "1234567890") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "CACAU", phone: "(123)4567890") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau borges', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', phone: '(123)4567890') + context "when names are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau borges", phone: "1234567890") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", phone: "(123)4567890") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau-borges', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau.Borges', phone: '(123)4567890') + context "when names are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau-borges", phone: "1234567890") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau.Borges", phone: "(123)4567890") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the names are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau', phone: '1234567890') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau borges', phone: '(123)4567890') + context "when the names are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "cacau", phone: "1234567890") + force_create(:supporter, nonprofit_id: np.id, name: "cacau borges", phone: "(123)4567890") expect(subject).to match_array([]) end @@ -338,139 +330,139 @@ end end - describe '.dupes_on_name_and_address' do + describe ".dupes_on_name_and_address" do subject { QuerySupporters.dupes_on_name_and_address(np.id) } - it 'finds supporters with the same name and address' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') + it "finds supporters with the same name and address" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when different names' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue') + context "when different names" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue") expect(subject).to match_array([]) end end - context 'when different addresses' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear.Waters.Avenue') + context "when different addresses" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear.Waters.Avenue") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue') + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue') + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue") expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_name_and_address(np.id, false) } - context 'when names are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'CACAU', address: 'Clear Waters Avenue') + context "when names are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "CACAU", address: "Clear Waters Avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacauborges', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue') + context "when names are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacauborges", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau-borges', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau.Borges', address: 'Clear Waters Avenue') + context "when names are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau-borges", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau.Borges", address: "Clear Waters Avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the names are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau borges', address: 'Clear Waters Avenue') + context "when the names are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "cacau", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "cacau borges", address: "Clear Waters Avenue") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue') + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue') + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue") expect(subject).to eq([]) end end - context 'when addresses are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'clear waters avenue') + context "when addresses are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "clear waters avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when addresses are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'ClearWatersAvenue') + context "when addresses are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "ClearWatersAvenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when addresses are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters . Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters - Avenue') + context "when addresses are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters . Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters - Avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the addresses are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Avenue, Clear Waters') + context "when the addresses are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Avenue, Clear Waters") expect(subject).to match_array([]) end @@ -478,149 +470,149 @@ end end - describe '.dupes_on_last_name_and_address_and_email' do + describe ".dupes_on_last_name_and_address_and_email" do subject { QuerySupporters.dupes_on_last_name_and_address_and_email(np.id) } - it 'finds supporters with the same last name and address and email' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope Borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_3 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope Schultz', address: 'Clear Waters Avenue', email: "email@example.com") - + it "finds supporters with the same last name and address and email" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope Borges", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope Schultz", address: "Clear Waters Avenue", email: "email@example.com") + expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when different names' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope Schultz', address: 'Clear Waters Avenue', email: "email@example.com") + context "when different names" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope Schultz", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to match_array([]) end end - context 'when different addresses' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear.Waters.Avenue') + context "when different addresses" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear.Waters.Avenue") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue', email: "email@example.com") + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue', email: "email@example.com") + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([]) end end - context 'when the email is nil' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue', email: nil) - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue', email: nil) + context "when the email is nil" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue", email: nil) + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue", email: nil) expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_name_and_address(np.id, false) } - context 'when names are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'CACAU', address: 'Clear Waters Avenue', email: "email@example.com") + context "when names are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau", address: "Clear Waters Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "CACAU", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacauborges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue', email: "email@example.com") + context "when names are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacauborges", address: "Clear Waters Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau-borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau.Borges', address: 'Clear Waters Avenue', email: "email@example.com") + context "when names are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "cacau-borges", address: "Clear Waters Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau.Borges", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the names are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau borges', address: 'Clear Waters Avenue', email: "email@example.com") + context "when the names are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "cacau", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "cacau borges", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: '', address: 'Clear Waters Avenue', email: "email@example.com") + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "", address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: nil, address: 'Clear Waters Avenue', email: "email@example.com") + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: nil, address: "Clear Waters Avenue", email: "email@example.com") expect(subject).to eq([]) end end - context 'when addresses are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'clear waters avenue', email: "email@example.com") + context "when addresses are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "clear waters avenue", email: "email@example.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when addresses are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'ClearWatersAvenue', email: "email@example.com") + context "when addresses are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "ClearWatersAvenue", email: "email@example.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when addresses are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters . Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters - Avenue', email: "email@example.com") + context "when addresses are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters . Avenue", email: "email@example.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters - Avenue", email: "email@example.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the addresses are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Clear Waters Avenue', email: "email@example.com") - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', address: 'Avenue, Clear Waters', email: "email@example.com") + context "when the addresses are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Clear Waters Avenue", email: "email@example.com") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", address: "Avenue, Clear Waters", email: "email@example.com") expect(subject).to match_array([]) end @@ -628,112 +620,112 @@ end end - describe '.dupes_on_phone_and_email' do + describe ".dupes_on_phone_and_email" do subject { QuerySupporters.dupes_on_phone_and_email(np.id) } - it 'finds supporters with the same phone and email' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com') + it "finds supporters with the same phone and email" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when different phones' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '1234567890', email: 'cacau@cacau.com') + context "when different phones" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, phone: "1234567890", email: "cacau@cacau.com") expect(subject).to match_array([]) end end - context 'when different emails' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@gmail.com') + context "when different emails" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@gmail.com") expect(subject).to match_array([]) end end - context 'when the phone is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '', email: 'cacau@cacau.com') + context "when the phone is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, phone: "", email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, phone: "", email: "cacau@cacau.com") expect(subject).to eq([]) end end - context 'when the phone is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: nil, email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: nil, email: 'cacau@cacau.com') + context "when the phone is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, phone: nil, email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, phone: nil, email: "cacau@cacau.com") expect(subject).to eq([]) end end - context 'when the email is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: '', phone: '123456789') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: '', phone: '123456789') + context "when the email is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: "", phone: "123456789") + force_create(:supporter, nonprofit_id: np.id, email: "", phone: "123456789") expect(subject).to eq([]) end end - context 'when the email is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: nil, phone: '123456789') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: nil, phone: '123456789') + context "when the email is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: nil, phone: "123456789") + force_create(:supporter, nonprofit_id: np.id, email: nil, phone: "123456789") expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_phone_and_email(np.id, false) } - context 'when emails are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'Cacau@Cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com') + context "when emails are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "Cacau@Cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when emails are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com ') + context "when emails are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com ") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the emails are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@gmail.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, phone: '123456789', email: 'cacau@cacau.com ') + context "when the emails are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@gmail.com") + force_create(:supporter, nonprofit_id: np.id, phone: "123456789", email: "cacau@cacau.com ") expect(subject).to match_array([]) end end - context 'when the email is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: '', phone: '123456789') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: '', phone: '123456789') + context "when the email is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: "", phone: "123456789") + force_create(:supporter, nonprofit_id: np.id, email: "", phone: "123456789") expect(subject).to eq([]) end end - context 'when the email is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: nil, phone: '123456789') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: nil, phone: '123456789') + context "when the email is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: nil, phone: "123456789") + force_create(:supporter, nonprofit_id: np.id, email: nil, phone: "123456789") expect(subject).to eq([]) end @@ -741,156 +733,156 @@ end end - describe '.dupes_on_name_and_email' do + describe ".dupes_on_name_and_email" do subject { QuerySupporters.dupes_on_name_and_email(np.id) } - it 'finds supporters with the same name and email' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') + it "finds supporters with the same name and email" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when different names' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', email: 'cacau@cacau.com') + context "when different names" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", email: "cacau@cacau.com") expect(subject).to match_array([]) end end - context 'when different emails' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@gmail.com') + context "when different emails" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@gmail.com") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: '', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: '', email: 'cacau@cacau.com') + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "", email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, name: "", email: "cacau@cacau.com") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: nil, email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: nil, email: 'cacau@cacau.com') + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: nil, email: "cacau@cacau.com") + force_create(:supporter, nonprofit_id: np.id, name: nil, email: "cacau@cacau.com") expect(subject).to eq([]) end end - context 'when the email is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: '', name: 'Cacau Borges') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: '', name: 'Cacau Borges') + context "when the email is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: "", name: "Cacau Borges") + force_create(:supporter, nonprofit_id: np.id, email: "", name: "Cacau Borges") expect(subject).to eq([]) end end - context 'when the email is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: nil, name: 'Cacau Borges') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: nil, name: 'Cacau Borges') + context "when the email is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: nil, name: "Cacau Borges") + force_create(:supporter, nonprofit_id: np.id, email: nil, name: "Cacau Borges") expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_name_and_email(np.id, false) } - context 'when emails are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'Cacau@Cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') + context "when emails are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "Cacau@Cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when emails are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com ') + context "when emails are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com ") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the emails are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@gmail.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com ') + context "when the emails are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@gmail.com") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com ") expect(subject).to match_array([]) end end - context 'when the email is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: '', name: 'Cacau Borges') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: '', name: 'Cacau Borges') + context "when the email is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: "", name: "Cacau Borges") + force_create(:supporter, nonprofit_id: np.id, email: "", name: "Cacau Borges") expect(subject).to eq([]) end end - context 'when the email is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: nil, name: 'Cacau Borges') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: nil, name: 'Cacau Borges') + context "when the email is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: nil, name: "Cacau Borges") + force_create(:supporter, nonprofit_id: np.id, email: nil, name: "Cacau Borges") expect(subject).to eq([]) end end - context 'when names are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@gmail.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'cacau borges', email: 'cacau@gmail.com') + context "when names are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@gmail.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "cacau borges", email: "cacau@gmail.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@cacau.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'CacauBorges', email: 'cacau@cacau.com') + context "when names are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@cacau.com") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "CacauBorges", email: "cacau@cacau.com") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the names are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau Borges', email: 'cacau@gmail.com') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', email: 'cacau@cacau.com ') + context "when the names are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau Borges", email: "cacau@gmail.com") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", email: "cacau@cacau.com ") expect(subject).to match_array([]) end end - context 'when the name is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: 'cacau@gmail.com', name: '') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: 'cacau@gmail.com', name: '') + context "when the name is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: "cacau@gmail.com", name: "") + force_create(:supporter, nonprofit_id: np.id, email: "cacau@gmail.com", name: "") expect(subject).to eq([]) end end - context 'when the name is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, email: 'cacau@gmail.com', name: nil) - supporter_2 = force_create(:supporter, nonprofit_id: np.id, email: 'cacau@gmail.com', name: nil) + context "when the name is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, email: "cacau@gmail.com", name: nil) + force_create(:supporter, nonprofit_id: np.id, email: "cacau@gmail.com", name: nil) expect(subject).to eq([]) end @@ -898,67 +890,67 @@ end end - describe '.dupes_on_address' do + describe ".dupes_on_address" do subject { QuerySupporters.dupes_on_address(np.id) } - it 'finds supporters with the same address' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue', zip_code: '32101') + it "finds supporters with the same address" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when the address is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: '', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: '', zip_code: '32101') + context "when the address is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the address is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: nil, zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: nil, zip_code: '32101') + context "when the address is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: nil, zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: nil, zip_code: "32101") expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_address(np.id, false) } - context 'when addresses are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'clear waters avenue', zip_code: '32101') + context "when addresses are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "clear waters avenue", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when addresses are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue 106', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear WatersAvenue 106', zip_code: '32101') + context "when addresses are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue 106", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear WatersAvenue 106", zip_code: "32101") expect(subject.first).to match_array([supporter_1.id, supporter_2.id]) end end - context 'when addresses are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue 106', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue - 106', zip_code: '32101') + context "when addresses are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue 106", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue - 106", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the addresses are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue 106', zip_code: '32101') + context "when the addresses are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue 106", zip_code: "32101") expect(subject).to match_array([]) end @@ -966,67 +958,67 @@ end end - describe '.dupes_on_address_without_zip_code' do + describe ".dupes_on_address_without_zip_code" do subject { QuerySupporters.dupes_on_address_without_zip_code(np.id) } - it 'finds supporters with the same address' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue') + it "finds supporters with the same address" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when the address is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: '') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: '') + context "when the address is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "") expect(subject).to eq([]) end end - context 'when the address is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: nil) - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: nil) + context "when the address is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: nil) + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: nil) expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_address_without_zip_code(np.id, false) } - context 'when addresses are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'clear waters avenue') + context "when addresses are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "clear waters avenue") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when addresses are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue 106') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear WatersAvenue 106') + context "when addresses are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue 106") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear WatersAvenue 106") expect(subject.first).to match_array([supporter_1.id, supporter_2.id]) end end - context 'when addresses are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue 106') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue - 106') + context "when addresses are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue 106") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue - 106") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the addresses are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', address: 'Clear Waters Avenue') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', address: 'Clear Waters Avenue 106') + context "when the addresses are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", address: "Clear Waters Avenue") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", address: "Clear Waters Avenue 106") expect(subject).to match_array([]) end @@ -1034,139 +1026,139 @@ end end - describe '.dupes_on_phone_and_email_and_address' do + describe ".dupes_on_phone_and_email_and_address" do subject { QuerySupporters.dupes_on_phone_and_email_and_address(np.id) } - it 'finds supporters with the same phone, email, and address' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') + it "finds supporters with the same phone, email, and address" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end - context 'when different addresses' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Park Avenue', zip_code: '32101') + context "when different addresses" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Park Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when different emails' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'penelope@penelope.com', address: 'Clear Waters Avenue', zip_code: '32101') + context "when different emails" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "penelope@penelope.com", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when different zip codes' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32102') + context "when different zip codes" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32102") expect(subject).to eq([]) end end - context 'when different phones' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567891', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') + context "when different phones" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567891", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the phone is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') + context "when the phone is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the phone is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') + context "when the phone is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the email is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: '', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: '', address: 'Clear Waters Avenue', zip_code: '32101') + context "when the email is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the email is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', address: 'Clear Waters Avenue', zip_code: '32101') + context "when the email is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the address is empty' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: '', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', address: '', zip_code: '32101') + context "when the address is empty" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", address: "", zip_code: "32101") expect(subject).to eq([]) end end - context 'when the address is nil' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', zip_code: '32101') + context "when the address is nil" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", zip_code: "32101") expect(subject).to eq([]) end end - context 'when not on strict mode' do + context "when not on strict mode" do subject { QuerySupporters.dupes_on_phone_and_email_and_address(np.id, false) } - context 'when addresses are the same but with different casing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'clear waters avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') + context "when addresses are the same but with different casing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "clear waters avenue", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with different spacing' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue 106', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear WatersAvenue 106', zip_code: '32101') + context "when names are the same but with different spacing" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue 106", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", address: "Clear WatersAvenue 106", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when names are the same but with special characters' do - it 'finds' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue 106', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue - 106', zip_code: '32101') + context "when names are the same but with special characters" do + it "finds" do + supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue 106", zip_code: "32101") + supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue - 106", zip_code: "32101") expect(subject).to eq([[supporter_1.id, supporter_2.id]]) end end - context 'when the addresses are not the same' do - it 'does not find' do - supporter_1 = force_create(:supporter, nonprofit_id: np.id, name: 'Cacau', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue', zip_code: '32101') - supporter_2 = force_create(:supporter, nonprofit_id: np.id, name: 'Penelope', phone: '1234567890', email: 'cacau@cacau.com', address: 'Clear Waters Avenue - 106', zip_code: '32101') + context "when the addresses are not the same" do + it "does not find" do + force_create(:supporter, nonprofit_id: np.id, name: "Cacau", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue", zip_code: "32101") + force_create(:supporter, nonprofit_id: np.id, name: "Penelope", phone: "1234567890", email: "cacau@cacau.com", address: "Clear Waters Avenue - 106", zip_code: "32101") expect(subject).to eq([]) end @@ -1174,30 +1166,30 @@ end end - describe '.for_export_enumerable' do - describe 'Just first name field' do - it 'when supporter has no name, just first name is blank' do - s = create(:supporter, name: '') + describe ".for_export_enumerable" do + describe "Just first name field" do + it "when supporter has no name, just first name is blank" do + s = create(:supporter, name: "") supporters = QuerySupporters.for_export_enumerable(s.nonprofit.id, {}).to_a expect(supporters[1][2]).to be_blank end - it 'when supporter has single name, just first name is filled' do - s = create(:supporter, name: 'Penelope') + it "when supporter has single name, just first name is filled" do + s = create(:supporter, name: "Penelope") supporters = QuerySupporters.for_export_enumerable(s.nonprofit.id, {}).to_a - expect(supporters[1][2]).to eq 'Penelope' + expect(supporters[1][2]).to eq "Penelope" end - it 'when supporter has a two word name, just first name is filled' do - s = create(:supporter, name: 'Penelope Rebecca') + it "when supporter has a two word name, just first name is filled" do + s = create(:supporter, name: "Penelope Rebecca") supporters = QuerySupporters.for_export_enumerable(s.nonprofit.id, {}).to_a - expect(supporters[1][2]).to eq 'Penelope' + expect(supporters[1][2]).to eq "Penelope" end - it 'when supporter has a three word name, just first name is filled' do - s = create(:supporter, name: 'Penelope Rebecca Schultz') + it "when supporter has a three word name, just first name is filled" do + s = create(:supporter, name: "Penelope Rebecca Schultz") supporters = QuerySupporters.for_export_enumerable(s.nonprofit.id, {}).to_a - expect(supporters[1][2]).to eq 'Penelope' + expect(supporters[1][2]).to eq "Penelope" end end end diff --git a/spec/lib/query/query_users_spec.rb b/spec/lib/query/query_users_spec.rb index 0464973b9..673d03a55 100644 --- a/spec/lib/query/query_users_spec.rb +++ b/spec/lib/query/query_users_spec.rb @@ -1,11 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe QueryUsers do - - describe '.nonprofit_user_emails', pending: true do - - before(:all) do + describe ".nonprofit_user_emails", pending: true do + before(:all) do # @np = Psql.execute(Qexpr.new.insert('nonprofits', [{name: 'xxyy'}])).first # # @users = Psql.execute(Qexpr.new.insert('users', [ @@ -42,15 +40,14 @@ # @email_settings.merge({user_id: @users[4]['id'], notify_payouts: false}), # @email_settings.merge({user_id: @users[5]['id'], notify_recurring_donations: false}), # ], {common_data: {nonprofit_id: @np['id']}, no_timestamps: true})) - end - + end - it 'Returns all users who have the respective setting enabled (or no settings set), and does not return people without the right role' do - expect(QueryUsers.nonprofit_user_emails(@np['id'], 'notify_payments').sort).to eq([0, 2, 3, 4, 5].map{|id| @users[id]['email']}.concat([@user_no_settings['email']]).sort) - expect(QueryUsers.nonprofit_user_emails(@np['id'], 'notify_campaigns').sort).to eq([0, 1, 3, 4, 5].map{|id| @users[id]['email']}.concat([@user_no_settings['email']]).sort) - expect(QueryUsers.nonprofit_user_emails(@np['id'], 'notify_events').sort).to eq([0, 1, 2, 4, 5].map{|id| @users[id]['email']}.concat([@user_no_settings['email']]).sort) - expect(QueryUsers.nonprofit_user_emails(@np['id'], 'notify_payouts').sort).to eq([0, 1, 2, 3, 5].map{|id| @users[id]['email']}.concat([@user_no_settings['email']]).sort) - expect(QueryUsers.nonprofit_user_emails(@np['id'], 'notify_recurring_donations').sort).to eq([0, 1, 2, 3, 4].map{|id| @users[id]['email']}.concat([@user_no_settings['email']]).sort) - end - end + it "Returns all users who have the respective setting enabled (or no settings set), and does not return people without the right role" do + expect(QueryUsers.nonprofit_user_emails(@np["id"], "notify_payments").sort).to eq([0, 2, 3, 4, 5].map { |id| @users[id]["email"] }.concat([@user_no_settings["email"]]).sort) + expect(QueryUsers.nonprofit_user_emails(@np["id"], "notify_campaigns").sort).to eq([0, 1, 3, 4, 5].map { |id| @users[id]["email"] }.concat([@user_no_settings["email"]]).sort) + expect(QueryUsers.nonprofit_user_emails(@np["id"], "notify_events").sort).to eq([0, 1, 2, 4, 5].map { |id| @users[id]["email"] }.concat([@user_no_settings["email"]]).sort) + expect(QueryUsers.nonprofit_user_emails(@np["id"], "notify_payouts").sort).to eq([0, 1, 2, 3, 5].map { |id| @users[id]["email"] }.concat([@user_no_settings["email"]]).sort) + expect(QueryUsers.nonprofit_user_emails(@np["id"], "notify_recurring_donations").sort).to eq([0, 1, 2, 3, 4].map { |id| @users[id]["email"] }.concat([@user_no_settings["email"]]).sort) + end + end end diff --git a/spec/lib/reassign_supporter_items_spec.rb b/spec/lib/reassign_supporter_items_spec.rb index 530bb82c2..e6283dc92 100644 --- a/spec/lib/reassign_supporter_items_spec.rb +++ b/spec/lib/reassign_supporter_items_spec.rb @@ -1,181 +1,179 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe ReassignSupporterItems do - let(:nonprofit) { create(:fv_poverty) } - let(:supporter) { nonprofit.supporters.create(name: 'Cacau', email: 'cacau@cacau.com') } - let(:other_supporter) { nonprofit.supporters.create(name: 'Eric') } - let(:row) { { 'Account Number' => '12345', 'Account Name' => 'Cacau' } } - let!(:etap_import) { create(:e_tap_import, nonprofit: nonprofit) } - - before do - etap_import.e_tap_import_journal_entries.create(row: row) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: supporter.supporter_notes.create(content: 'Some note')) + let(:nonprofit) { create(:fv_poverty) } + let(:supporter) { nonprofit.supporters.create(name: "Cacau", email: "cacau@cacau.com") } + let(:other_supporter) { nonprofit.supporters.create(name: "Eric") } + let(:row) { {"Account Number" => "12345", "Account Name" => "Cacau"} } + let!(:etap_import) { create(:e_tap_import, nonprofit: nonprofit) } + + before do + etap_import.e_tap_import_journal_entries.create(row: row) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: supporter.supporter_notes.create(content: "Some note")) + end + + describe "#perform" do + context "when all items are assigned to the correct supporter" do + it "returns an empty array" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, supporter_id: supporter.id, row: row) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: supporter.supporter_notes.create(content: "Some note")).item + expect(described_class.perform(etap_import)).to eq([]) + end + + it "does not reassign" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, supporter_id: supporter.id, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: supporter.supporter_notes.create(content: "Some note")).item + expect { described_class.perform(etap_import) }.not_to change { item.supporter } + end end - describe '#perform' do - - context 'when all items are assigned to the correct supporter' do - it 'returns an empty array' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, supporter_id: supporter.id, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: supporter.supporter_notes.create(content: 'Some note')).item - expect(described_class.perform(etap_import)).to eq([]) - end - - it 'does not reassign' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, supporter_id: supporter.id, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: supporter.supporter_notes.create(content: 'Some note')).item - expect { described_class.perform(etap_import) }.not_to change { item.supporter } - end + context "when some items are assigned to the wrong supporter" do + it "reassigns the item to the correct supporter" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.donations.create(amount: 100, supporter: other_supporter, nonprofit: nonprofit)).item + + expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) + end + + it "reassigns the activity to the correct supporter" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + activity = Activity.where(attachment_type: "SupporterEmail", attachment_id: item.id).first + + expect { described_class.perform(etap_import) }.to change { activity.reload.supporter }.from(other_supporter).to(supporter) + end + + it "returns an empty array" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.donations.create(amount: 100, supporter: other_supporter, nonprofit: nonprofit)) + + expect(described_class.perform(etap_import)).to eq([]) + end + + it "records the item reassignment" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + + described_class.perform(etap_import) + expect(etap_import.reassignments.first.attributes.except("id", "created_at", "updated_at")).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: item.id, item_type: "SupporterNote", e_tap_import_id: etap_import.id}.stringify_keys) + end + + it "records the activity reassignment" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + activity = Activity.where(attachment_type: "SupporterEmail", attachment_id: item.id).first + + described_class.perform(etap_import) + expect(etap_import.reassignments.last.attributes.except("id", "created_at", "updated_at")).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: activity.id, item_type: "Activity", e_tap_import_id: etap_import.id}.stringify_keys) + end + + context "when the contact does not have a matching supporter by account id" do + before do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "54321"]]) end - context 'when some items are assigned to the wrong supporter' do - it 'reassigns the item to the correct supporter' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.donations.create(amount: 100, supporter: other_supporter, nonprofit: nonprofit)).item - - expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) - end - - it 'reassigns the activity to the correct supporter' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - activity = Activity.where(attachment_type: 'SupporterEmail', attachment_id: item.id).first - - - expect { described_class.perform(etap_import) }.to change { activity.reload.supporter }.from(other_supporter).to(supporter) - end - - it 'returns an empty array' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.donations.create(amount: 100, supporter: other_supporter, nonprofit: nonprofit)) - - expect(described_class.perform(etap_import)).to eq([]) - end - - it 'records the item reassignment' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - - described_class.perform(etap_import) - expect(etap_import.reassignments.first.attributes.except('id', 'created_at', 'updated_at')).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: item.id, item_type: 'SupporterNote', e_tap_import_id: etap_import.id}.stringify_keys) - end - - it 'records the activity reassignment' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - activity = Activity.where(attachment_type: 'SupporterEmail', attachment_id: item.id).first - - described_class.perform(etap_import) - expect(etap_import.reassignments.last.attributes.except('id', 'created_at', 'updated_at')).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: activity.id, item_type: 'Activity', e_tap_import_id: etap_import.id}.stringify_keys) - end - - context 'when the contact does not have a matching supporter by account id' do - before do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '54321' ]]) - end - - it 'tries to find by the account name or email' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Email' => 'cacau@cacau.com', 'Account Number' => '54321'}) - etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')) - allow(ETapImportContact) - .to receive(:find_by_account_name) - .with('Cacau', 'cacau@cacau.com', '12345') - .twice - - described_class.perform(etap_import) - expect(ETapImportContact) - .to have_received(:find_by_account_name) - .with('Cacau', 'cacau@cacau.com', '12345') - .twice - end - - context 'when there is other corresponding contact' do - it 'reassigns the item to the correct supporter' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Account Name' => 'Cacau', 'Account Number' => '54321'}) - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - - expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) - end - - it 'reassigns the activity to the correct supporter' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Email' => 'cacau@cacau.com', 'Account Number' => '54321'}) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - activity = Activity.where(attachment_type: 'SupporterEmail', attachment_id: item.id).first - - expect { described_class.perform(etap_import) }.to change { activity.reload.supporter }.from(other_supporter).to(supporter) - end - - it 'returns an empty array' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Account Name' => 'Cacau', 'Account Number' => '54321'}) - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - - expect(described_class.perform(etap_import)).to eq([]) - end - - it 'records the item reassignment' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Account Name' => 'Cacau', 'Account Number' => '54321'}) - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - - described_class.perform(etap_import) - expect(etap_import.reassignments.first.attributes.except('id', 'created_at', 'updated_at')).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: item.id, item_type: 'SupporterNote', e_tap_import_id: etap_import.id}.stringify_keys) - end - - it 'records the activity reassignment' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Email' => 'cacau@cacau.com', 'Account Number' => '54321'}) - create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - activity = Activity.where(attachment_type: 'SupporterEmail', attachment_id: item.id).first - - described_class.perform(etap_import) - expect(etap_import.reassignments.find_by(item: activity).attributes.except('id', 'created_at', 'updated_at')).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: activity.id, item_type: 'Activity', e_tap_import_id: etap_import.id}.stringify_keys) - end - end - - context 'when there are no matches' do - it 'returns an array with the bad data' do - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: { 'Account Name' => 'Penelope', 'Account Number' => '54321'}) - e_tap_import_contact = create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item - - expect(described_class.perform(etap_import).first).to include(:etije, :etije_id, :supp_through_contact, :journal_entries_to_items_with_wrong_supporter) - end - end - end + it "tries to find by the account name or email" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Email" => "cacau@cacau.com", "Account Number" => "54321"}) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")) + allow(ETapImportContact) + .to receive(:find_by_account_name) + .with("Cacau", "cacau@cacau.com", "12345") + .twice + + described_class.perform(etap_import) + expect(ETapImportContact) + .to have_received(:find_by_account_name) + .with("Cacau", "cacau@cacau.com", "12345") + .twice end - end - describe '#revert_reassignments_from_supporter' do - it 'reverts the reassignments from a supporter' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) + context "when there is other corresponding contact" do + it "reassigns the item to the correct supporter" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Account Name" => "Cacau", "Account Number" => "54321"}) create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) - expect { described_class.revert_reassignments_from_supporter(supporter) }.to change { item.reload.supporter }.from(supporter).to(other_supporter) + end + + it "reassigns the activity to the correct supporter" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Email" => "cacau@cacau.com", "Account Number" => "54321"}) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + activity = Activity.where(attachment_type: "SupporterEmail", attachment_id: item.id).first + + expect { described_class.perform(etap_import) }.to change { activity.reload.supporter }.from(other_supporter).to(supporter) + end + + it "returns an empty array" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Account Name" => "Cacau", "Account Number" => "54321"}) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + + expect(described_class.perform(etap_import)).to eq([]) + end + + it "records the item reassignment" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Account Name" => "Cacau", "Account Number" => "54321"}) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + + described_class.perform(etap_import) + expect(etap_import.reassignments.first.attributes.except("id", "created_at", "updated_at")).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: item.id, item_type: "SupporterNote", e_tap_import_id: etap_import.id}.stringify_keys) + end + + it "records the activity reassignment" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Email" => "cacau@cacau.com", "Account Number" => "54321"}) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + activity = Activity.where(attachment_type: "SupporterEmail", attachment_id: item.id).first + + described_class.perform(etap_import) + expect(etap_import.reassignments.find_by(item: activity).attributes.except("id", "created_at", "updated_at")).to match({source_supporter_id: other_supporter.id, target_supporter_id: supporter.id, item_id: activity.id, item_type: "Activity", e_tap_import_id: etap_import.id}.stringify_keys) + end end - end - describe '#revert_all_reassignments' do - it 'reverts reassignments from an etap import' do - InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [['E-Tapestry Id #', '12345' ]]) + context "when there are no matches" do + it "returns an array with the bad data" do + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: {"Account Name" => "Penelope", "Account Number" => "54321"}) create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) - item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: 'Some note')).item + etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item - expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) - expect { described_class.revert_all_reassignments(etap_import) }.to change { item.reload.supporter }.from(supporter).to(other_supporter) + expect(described_class.perform(etap_import).first).to include(:etije, :etije_id, :supp_through_contact, :journal_entries_to_items_with_wrong_supporter) + end end + end + end + end + + describe "#revert_reassignments_from_supporter" do + it "reverts the reassignments from a supporter" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + + expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) + expect { described_class.revert_reassignments_from_supporter(supporter) }.to change { item.reload.supporter }.from(supporter).to(other_supporter) + end + end + + describe "#revert_all_reassignments" do + it "reverts reassignments from an etap import" do + InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [["E-Tapestry Id #", "12345"]]) + create(:e_tap_import_contact, nonprofit: nonprofit, e_tap_import: etap_import, row: row) + item = etap_import.e_tap_import_journal_entries.first.journal_entries_to_items.create(item: other_supporter.supporter_notes.create(content: "Some note")).item + + expect { described_class.perform(etap_import) }.to change { item.reload.supporter }.from(other_supporter).to(supporter) + expect { described_class.revert_all_reassignments(etap_import) }.to change { item.reload.supporter }.from(supporter).to(other_supporter) end + end end diff --git a/spec/lib/retrieve/retrieve_active_record_items_spec.rb b/spec/lib/retrieve/retrieve_active_record_items_spec.rb index 8dc2eaa05..0d3fb4954 100644 --- a/spec/lib/retrieve/retrieve_active_record_items_spec.rb +++ b/spec/lib/retrieve/retrieve_active_record_items_spec.rb @@ -1,75 +1,74 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe RetrieveActiveRecordItems do - describe '.retrieve' do - let(:item) {force_create(:supporter)} - let(:item2) {force_create(:nonprofit)} - it 'raises if not a class for key' do - expect {RetrieveActiveRecordItems.retrieve('item' => 1)}.to raise_error(ArgumentError) + describe ".retrieve" do + let(:item) { force_create(:supporter) } + let(:item2) { force_create(:nonprofit) } + it "raises if not a class for key" do + expect { RetrieveActiveRecordItems.retrieve("item" => 1) }.to raise_error(ArgumentError) end - it 'raises if optional is false and value is nil' do - expect{RetrieveActiveRecordItems.retrieve(ActiveRecord => nil)}.to raise_error(ArgumentError) + it "raises if optional is false and value is nil" do + expect { RetrieveActiveRecordItems.retrieve(ActiveRecord => nil) }.to raise_error(ArgumentError) end - it 'raises if optional is true and value is not integer' do - expect{RetrieveActiveRecordItems.retrieve({ActiveRecord => 'number'}, true)}.to raise_error(ArgumentError) + it "raises if optional is true and value is not integer" do + expect { RetrieveActiveRecordItems.retrieve({ActiveRecord => "number"}, true) }.to raise_error(ArgumentError) end - it 'raises if optional is true and value is not positive integer' do - expect{RetrieveActiveRecordItems.retrieve({ActiveRecord => -1}, true)}.to raise_error(ArgumentError) + it "raises if optional is true and value is not positive integer" do + expect { RetrieveActiveRecordItems.retrieve({ActiveRecord => -1}, true) }.to raise_error(ArgumentError) end - it 'gets valid item as optional or not' do - expected = {Supporter => item, Nonprofit => item2} + it "gets valid item as optional or not" do + expected = {Supporter => item, Nonprofit => item2} expect(RetrieveActiveRecordItems.retrieve({Supporter => item.id, Nonprofit => item2.id})).to eq expected expect(RetrieveActiveRecordItems.retrieve({Supporter => item.id, Nonprofit => item2.id}, true)).to eq expected end - it 'raises if youve put in an invalid id' do - expect {RetrieveActiveRecordItems.retrieve({Supporter => 5555, Nonprofit => item2.id})}.to raise_error(ParamValidation::ValidationError) - expect {RetrieveActiveRecordItems.retrieve({Supporter => 5555, Nonprofit => item2.id}, true)}.to raise_error(ParamValidation::ValidationError) + it "raises if youve put in an invalid id" do + expect { RetrieveActiveRecordItems.retrieve({Supporter => 5555, Nonprofit => item2.id}) }.to raise_error(ParamValidation::ValidationError) + expect { RetrieveActiveRecordItems.retrieve({Supporter => 5555, Nonprofit => item2.id}, true) }.to raise_error(ParamValidation::ValidationError) end - it 'gets valid item as optional or not' do - expected = {Supporter => item, User => nil} + it "gets valid item as optional or not" do + expected = {Supporter => item, User => nil} expect(RetrieveActiveRecordItems.retrieve({Supporter => item.id, User => nil}, true)).to eq expected end - end - describe '.retrieve_from_keys' do - let(:item) {force_create(:supporter)} - let(:item2) {force_create(:nonprofit)} - it 'raises if not a class for key' do - expect {RetrieveActiveRecordItems.retrieve_from_keys({},'item' => 1)}.to raise_error(ArgumentError) + describe ".retrieve_from_keys" do + let(:item) { force_create(:supporter) } + let(:item2) { force_create(:nonprofit) } + it "raises if not a class for key" do + expect { RetrieveActiveRecordItems.retrieve_from_keys({}, "item" => 1) }.to raise_error(ArgumentError) end - it 'raises if optional is false and value is nil' do - expect{RetrieveActiveRecordItems.retrieve_from_keys({data: nil}, Nonprofit => :data)}.to raise_error(ParamValidation::ValidationError) + it "raises if optional is false and value is nil" do + expect { RetrieveActiveRecordItems.retrieve_from_keys({data: nil}, Nonprofit => :data) }.to raise_error(ParamValidation::ValidationError) end - it 'raises if optional is true and value is not integer' do - expect{RetrieveActiveRecordItems.retrieve_from_keys({data: ''},{Nonprofit => :data}, true)}.to raise_error(ParamValidation::ValidationError) + it "raises if optional is true and value is not integer" do + expect { RetrieveActiveRecordItems.retrieve_from_keys({data: ""}, {Nonprofit => :data}, true) }.to raise_error(ParamValidation::ValidationError) end - it 'raises if optional is true and value is not positive integer' do - expect{RetrieveActiveRecordItems.retrieve_from_keys({data: -1 }, {Nonprofit => :data}, true)}.to raise_error(ParamValidation::ValidationError) + it "raises if optional is true and value is not positive integer" do + expect { RetrieveActiveRecordItems.retrieve_from_keys({data: -1}, {Nonprofit => :data}, true) }.to raise_error(ParamValidation::ValidationError) end - it 'gets valid item as optional or not' do - expected = {supporter: item, nonprofit: item2} + it "gets valid item as optional or not" do + expected = {supporter: item, nonprofit: item2} expect(RetrieveActiveRecordItems.retrieve_from_keys({supporter: item.id, nonprofit: item2.id}, {Supporter => :supporter, Nonprofit => :nonprofit})).to eq expected expect(RetrieveActiveRecordItems.retrieve_from_keys({supporter: item.id, nonprofit: item2.id}, {Supporter => :supporter, Nonprofit => :nonprofit}, true)).to eq expected end - it 'raises if youve put in an invalid id' do - expect {RetrieveActiveRecordItems.retrieve_from_keys({supporter: 5555, nonprofit: item2.id}, {Supporter => :supporter, Nonprofit => :nonprofit})}.to raise_error(ParamValidation::ValidationError) - expect {RetrieveActiveRecordItems.retrieve_from_keys({supporter: 5555, nonprofit: item2.id},{Supporter => :supporter, Nonprofit => :nonprofit}, true)}.to raise_error(ParamValidation::ValidationError) + it "raises if youve put in an invalid id" do + expect { RetrieveActiveRecordItems.retrieve_from_keys({supporter: 5555, nonprofit: item2.id}, {Supporter => :supporter, Nonprofit => :nonprofit}) }.to raise_error(ParamValidation::ValidationError) + expect { RetrieveActiveRecordItems.retrieve_from_keys({supporter: 5555, nonprofit: item2.id}, {Supporter => :supporter, Nonprofit => :nonprofit}, true) }.to raise_error(ParamValidation::ValidationError) end - it 'gets valid item as optional or not' do - expected = {:supporter => item, :user => nil} + it "gets valid item as optional or not" do + expected = {supporter: item, user: nil} expect(RetrieveActiveRecordItems.retrieve_from_keys({supporter: item.id, user: nil}, {Supporter => :supporter, User => :user}, true)).to eq expected end end -end \ No newline at end of file +end diff --git a/spec/lib/slug_copy_naming_algorithm_spec.rb b/spec/lib/slug_copy_naming_algorithm_spec.rb index 67cabeeca..bb1037397 100644 --- a/spec/lib/slug_copy_naming_algorithm_spec.rb +++ b/spec/lib/slug_copy_naming_algorithm_spec.rb @@ -1,44 +1,42 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe SlugCopyNamingAlgorithm do - describe '.create_copy_name' do + describe ".create_copy_name" do before(:all) { - Timecop.freeze(2020,5,4) + Timecop.freeze(2020, 5, 4) } after(:all) { - Timecop.return + Timecop.return } def set_name(name) @name = name end - let(:short_slug) { "slug_name"} - let(:short_slug_copy_today) { "slug_name_copy_00"} - let(:short_slug_copy_today_plus_1) { "slug_name_copy_01"} - let(:copy_base) {"slug_name_copy"} - - - let(:nonprofit) {force_create(:nonprofit)} - - - describe 'events' do - - let(:event) {force_create(:event, :slug => @name, nonprofit: nonprofit)} - let(:event2) {force_create(:event, :slug => @name2, nonprofit:nonprofit)} - let(:events_at_max_copies) { (0..30).collect{|i| - force_create(:event, slug: "#{@copy_base}_#{"%02d" % i}", nonprofit:nonprofit) - }} - let(:algo) {SlugCopyNamingAlgorithm.new(Event, nonprofit.id)} - describe 'event slugs' do - - it 'not a copy' do + let(:short_slug) { "slug_name" } + let(:short_slug_copy_today) { "slug_name_copy_00" } + let(:short_slug_copy_today_plus_1) { "slug_name_copy_01" } + let(:copy_base) { "slug_name_copy" } + + let(:nonprofit) { force_create(:nonprofit) } + + describe "events" do + let(:event) { force_create(:event, slug: @name, nonprofit: nonprofit) } + let(:event2) { force_create(:event, slug: @name2, nonprofit: nonprofit) } + let(:events_at_max_copies) { + (0..30).collect { |i| + force_create(:event, slug: "#{@copy_base}_#{"%02d" % i}", nonprofit: nonprofit) + } + } + let(:algo) { SlugCopyNamingAlgorithm.new(Event, nonprofit.id) } + describe "event slugs" do + it "not a copy" do @name = short_slug event expect(algo.create_copy_name(@name)).to eq short_slug_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = short_slug @name2 = short_slug_copy_today event @@ -47,30 +45,28 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_slug_copy_today_plus_1 end - it 'has 30 as max copies' do + it "has 30 as max copies" do expect(algo.max_copies).to eq 30 end - end - - end - describe 'campaigns' do - let(:campaign) {force_create(:campaign, :slug => @name, nonprofit: nonprofit)} - let(:campaign2) {force_create(:campaign, :slug => @name2, nonprofit:nonprofit)} - let(:campaigns_at_max_copies) { (0..30).collect{|i| - force_create(:campaign, slug: "#{@copy_base}_#{"%02d" % i}", nonprofit:nonprofit) - }} - let(:algo) {SlugCopyNamingAlgorithm.new(Campaign, nonprofit.id)} - describe 'campaign slugs' do - - it 'not a copy' do + describe "campaigns" do + let(:campaign) { force_create(:campaign, slug: @name, nonprofit: nonprofit) } + let(:campaign2) { force_create(:campaign, slug: @name2, nonprofit: nonprofit) } + let(:campaigns_at_max_copies) { + (0..30).collect { |i| + force_create(:campaign, slug: "#{@copy_base}_#{"%02d" % i}", nonprofit: nonprofit) + } + } + let(:algo) { SlugCopyNamingAlgorithm.new(Campaign, nonprofit.id) } + describe "campaign slugs" do + it "not a copy" do @name = short_slug campaign expect(algo.create_copy_name(@name)).to eq short_slug_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = short_slug @name2 = short_slug_copy_today campaign @@ -79,13 +75,10 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_slug_copy_today_plus_1 end - it 'has 30 as max copies' do + it "has 30 as max copies" do expect(algo.max_copies).to eq 30 end - - end end end end - diff --git a/spec/lib/slug_nonprofit_naming_algorithm_spec.rb b/spec/lib/slug_nonprofit_naming_algorithm_spec.rb index 2a58055f3..50d54ab4b 100644 --- a/spec/lib/slug_nonprofit_naming_algorithm_spec.rb +++ b/spec/lib/slug_nonprofit_naming_algorithm_spec.rb @@ -1,49 +1,48 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe SlugNonprofitNamingAlgorithm do - describe '.create_copy_name' do + describe ".create_copy_name" do before(:all) { - Timecop.freeze(2020,5,4) + Timecop.freeze(2020, 5, 4) } after(:all) { - Timecop.return + Timecop.return } def set_name(name) @name = name end - let(:short_slug) { "slug_name"} - let(:short_slug_copy_today) { "slug_name-00"} - let(:short_slug_copy_today_plus_1) { "slug_name-01"} - let(:copy_base) {"slug_name"} - - let(:state_slug) {'state_slug'} - let(:city_slug) {'city_slug'} - let(:not_our_state_slug) {'not_our_state_slug'} - let(:not_our_city_slug) {'not_our_city_slug'} - - - - describe 'nonprofits' do - let(:nonprofit) {force_create(:nonprofit, :slug => @name, state_code_slug: state_slug, city_slug: city_slug)} - let(:nonprofit2) {force_create(:nonprofit, :slug => @name2, state_code_slug: state_slug, city_slug: city_slug)} - let(:nonprofit_in_other_city) {force_create(:nonprofit, :slug => @name, state_code_slug: state_slug, city_slug: not_our_city_slug)} - let(:nonprofit_in_other_state) {force_create(:nonprofit, :slug => @name, state_code_slug: not_our_state_slug, city_slug: city_slug)} - let(:nonprofit_at_max_copies) { (0..99).collect{|i| - force_create(:nonprofit, slug: "#{@copy_base}-#{"%02d" % i}", state_code_slug: state_slug, city_slug: city_slug) - }} - let(:algo) {SlugNonprofitNamingAlgorithm.new(state_slug,city_slug)} - - describe 'nonprofit slugs' do - - it 'not a copy' do + let(:short_slug) { "slug_name" } + let(:short_slug_copy_today) { "slug_name-00" } + let(:short_slug_copy_today_plus_1) { "slug_name-01" } + let(:copy_base) { "slug_name" } + + let(:state_slug) { "state_slug" } + let(:city_slug) { "city_slug" } + let(:not_our_state_slug) { "not_our_state_slug" } + let(:not_our_city_slug) { "not_our_city_slug" } + + describe "nonprofits" do + let(:nonprofit) { force_create(:nonprofit, slug: @name, state_code_slug: state_slug, city_slug: city_slug) } + let(:nonprofit2) { force_create(:nonprofit, slug: @name2, state_code_slug: state_slug, city_slug: city_slug) } + let(:nonprofit_in_other_city) { force_create(:nonprofit, slug: @name, state_code_slug: state_slug, city_slug: not_our_city_slug) } + let(:nonprofit_in_other_state) { force_create(:nonprofit, slug: @name, state_code_slug: not_our_state_slug, city_slug: city_slug) } + let(:nonprofit_at_max_copies) { + (0..99).collect { |i| + force_create(:nonprofit, slug: "#{@copy_base}-#{"%02d" % i}", state_code_slug: state_slug, city_slug: city_slug) + } + } + let(:algo) { SlugNonprofitNamingAlgorithm.new(state_slug, city_slug) } + + describe "nonprofit slugs" do + it "not a copy" do @name = short_slug nonprofit expect(algo.create_copy_name(@name)).to eq short_slug_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = short_slug @name2 = short_slug_copy_today nonprofit @@ -54,13 +53,10 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_slug_copy_today_plus_1 end - it 'it has 99 as max copies' do + it "it has 99 as max copies" do expect(algo.max_copies).to eq 99 end - - end end end end - diff --git a/spec/lib/slug_p2p_campaign_naming_algorithm_spec.rb b/spec/lib/slug_p2p_campaign_naming_algorithm_spec.rb index 1353180e9..19bc259e4 100644 --- a/spec/lib/slug_p2p_campaign_naming_algorithm_spec.rb +++ b/spec/lib/slug_p2p_campaign_naming_algorithm_spec.rb @@ -1,43 +1,42 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe SlugP2pCampaignNamingAlgorithm do - describe '.create_copy_name' do + describe ".create_copy_name" do before(:all) { - Timecop.freeze(2020,5,4) + Timecop.freeze(2020, 5, 4) } after(:all) { - Timecop.return + Timecop.return } def set_name(name) @name = name end - let(:short_slug) { "slug_name"} - let(:short_slug_copy_today) { "slug_name_000"} - let(:short_slug_copy_today_plus_1) { "slug_name_001"} - let(:copy_base) {"slug_name"} - - - let(:nonprofit) {force_create(:nonprofit)} - - - describe 'campaigns' do - let(:campaign) {force_create(:campaign, :slug => @name, nonprofit: nonprofit, deleted:true)} - let(:campaign2) {force_create(:campaign, :slug => @name2, nonprofit:nonprofit)} - let(:campaigns_at_max_copies) { (0..999).collect{|i| - force_create(:campaign, slug: "#{@copy_base}_#{"%03d" % i}", nonprofit:nonprofit) - }} - let(:algo) {SlugP2pCampaignNamingAlgorithm.new( nonprofit.id)} - describe 'campaign slugs' do - - it 'not a copy' do + let(:short_slug) { "slug_name" } + let(:short_slug_copy_today) { "slug_name_000" } + let(:short_slug_copy_today_plus_1) { "slug_name_001" } + let(:copy_base) { "slug_name" } + + let(:nonprofit) { force_create(:nonprofit) } + + describe "campaigns" do + let(:campaign) { force_create(:campaign, slug: @name, nonprofit: nonprofit, deleted: true) } + let(:campaign2) { force_create(:campaign, slug: @name2, nonprofit: nonprofit) } + let(:campaigns_at_max_copies) { + (0..999).collect { |i| + force_create(:campaign, slug: "#{@copy_base}_#{"%03d" % i}", nonprofit: nonprofit) + } + } + let(:algo) { SlugP2pCampaignNamingAlgorithm.new(nonprofit.id) } + describe "campaign slugs" do + it "not a copy" do @name = short_slug campaign expect(algo.create_copy_name(@name)).to eq short_slug_copy_today end - it 'one copy exists' do + it "one copy exists" do @name = short_slug @name2 = short_slug_copy_today campaign @@ -46,11 +45,10 @@ def set_name(name) expect(algo.create_copy_name(@name2)).to eq short_slug_copy_today_plus_1 end - it 'has 999 as the max_copies' do + it "has 999 as the max_copies" do expect(algo.max_copies).to eq 999 end end end end end - diff --git a/spec/lib/stripe_account_utils_spec.rb b/spec/lib/stripe_account_utils_spec.rb index db26c78c4..44414f763 100644 --- a/spec/lib/stripe_account_utils_spec.rb +++ b/spec/lib/stripe_account_utils_spec.rb @@ -1,7 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'stripe' -require 'stripe_mock' +require "rails_helper" +require "stripe" +require "stripe_mock" describe StripeAccountUtils do around(:each) do |example| @@ -10,47 +10,47 @@ end end - let(:nonprofit) { force_create(:nonprofit)} - let(:nonprofit_with_bad_values) { force_create(:nonprofit, state_code: "invalid", zip_code: 'not valid', website: 'invalid_url', email: 'penelope@email.email')} + let(:nonprofit) { force_create(:nonprofit) } + let(:nonprofit_with_bad_values) { force_create(:nonprofit, state_code: "invalid", zip_code: "not valid", website: "invalid_url", email: "penelope@email.email") } - describe '.find_or_create' do - describe 'param validation' do - it 'basic param validation' do - expect { StripeAccountUtils.find_or_create(nil)}.to(raise_error{|error| + describe ".find_or_create" do + describe "param validation" do + it "basic param validation" do + expect { StripeAccountUtils.find_or_create(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [{:key => :nonprofit_id, :name => :required}, - {:key => :nonprofit_id, :name => :is_integer}]) + expect_validation_errors(error.data, [{key: :nonprofit_id, name: :required}, + {key: :nonprofit_id, name: :is_integer}]) }) end - it 'validate np' do - expect { StripeAccountUtils.find_or_create(5555)}.to(raise_error{|error| + it "validate np" do + expect { StripeAccountUtils.find_or_create(5555) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [{:key => :nonprofit_id}]) + expect_validation_errors(error.data, [{key: :nonprofit_id}]) }) end end # basically the same as running create - describe 'creates new Stripe Account if none is set exists' do - let!(:result) {StripeAccountUtils.find_or_create(nonprofit.id)} + describe "creates new Stripe Account if none is set exists" do + let!(:result) { StripeAccountUtils.find_or_create(nonprofit.id) } - it 'returns a Stripe acct id' do + it "returns a Stripe acct id" do expect(result).to_not be_blank end - it 'sets the Account values on Stripe' do + it "sets the Account values on Stripe" do expect { - saved_account = Stripe::Account.retrieve(result) + Stripe::Account.retrieve(result) }.to_not raise_error end - it 'updates the nonprofit itself' do + it "updates the nonprofit itself" do np = Nonprofit.find(nonprofit.id) expect(np.stripe_account_id).to eq result end end - describe 'get stripe account from database' do - let(:stripe_acct_id) { 'stripe_account_id'} + describe "get stripe account from database" do + let(:stripe_acct_id) { "stripe_account_id" } let!(:result) { nonprofit.stripe_account_id = stripe_acct_id @@ -60,88 +60,81 @@ StripeAccountUtils.find_or_create(nonprofit.id) } - it 'returns the expected id' do + it "returns the expected id" do expect(result).to eq stripe_acct_id end end end - - - describe '.create' do - it 'param validation' do - expect { StripeAccountUtils.create(nil)}.to(raise_error{|error| + describe ".create" do + it "param validation" do + expect { StripeAccountUtils.create(nil) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error.data, [{:key => :np, :name => :required}, - {:key => :np, :name => :is_a}]) + expect_validation_errors(error.data, [{key: :np, name: :required}, + {key: :np, name: :is_a}]) }) end end - describe 'testing with valid nonprofit' do - it 'handles Stripe errors properly' do + describe "testing with valid nonprofit" do + it "handles Stripe errors properly" do StripeMockHelper.prepare_error(Stripe::StripeError.new, :new_account) - expect { StripeAccountUtils.create(nonprofit)}.to(raise_error{|error| + expect { StripeAccountUtils.create(nonprofit) }.to(raise_error { |error| expect(error).to be_a Stripe::StripeError expect(nonprofit.stripe_account_id).to be_blank - }) end - describe 'saves properly without org email' do - - let!(:result) { StripeAccountUtils.create(nonprofit)} + describe "saves properly without org email" do + let!(:result) { StripeAccountUtils.create(nonprofit) } - it 'returns a Stripe acct id' do + it "returns a Stripe acct id" do expect(result).to_not be_blank end - it 'sets the Account values on Stripe' do + it "sets the Account values on Stripe" do expect { - saved_account = Stripe::Account.retrieve(result) + Stripe::Account.retrieve(result) }.to_not raise_error end - it 'updates the nonprofit itself' do + it "updates the nonprofit itself" do np = Nonprofit.find(nonprofit.id) expect(np.stripe_account_id).to eq result end end - describe 'saves properly without org email' do - - before(:each){ + describe "saves properly without org email" do + before(:each) { nonprofit.email = nil nonprofit.save! role } - let(:admin_role_email) { "email_user@email.email"} - let(:user) { force_create(:user, email: admin_role_email)} - let(:role) { force_create(:role, user: user, host: nonprofit, name: :nonprofit_admin)} - + let(:admin_role_email) { "email_user@email.email" } + let(:user) { force_create(:user, email: admin_role_email) } + let(:role) { force_create(:role, user: user, host: nonprofit, name: :nonprofit_admin) } - let(:result) { StripeAccountUtils.create(nonprofit)} - - it 'returns a Stripe acct id' do + let(:result) { StripeAccountUtils.create(nonprofit) } + it "returns a Stripe acct id" do expect(result).to_not be_blank end - it 'sets the Account values on Stripe' do - expect { - saved_account = Stripe::Account.retrieve(result) + it "sets the Account values on Stripe" do + expect { + Stripe::Account.retrieve(result) }.to_not raise_error end - it 'updates the nonprofit itself' do + it "updates the nonprofit itself" do result np = Nonprofit.find(nonprofit.id) expect(np.stripe_account_id).to eq result end - it 'sets the requested_capabilities to card_payments and transfers' do + it "sets the requested_capabilities to card_payments and transfers" do saved_account = Stripe::Account.retrieve(result) - expect(saved_account.requested_capabilities).to eq ['card_payments', 'transfers'] + expect(saved_account.requested_capabilities).to eq ["card_payments", "transfers"] end end end diff --git a/spec/lib/supporter_interpolation_dictionary_spec.rb b/spec/lib/supporter_interpolation_dictionary_spec.rb index e01c083b3..61419dc26 100644 --- a/spec/lib/supporter_interpolation_dictionary_spec.rb +++ b/spec/lib/supporter_interpolation_dictionary_spec.rb @@ -1,55 +1,55 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe SupporterInterpolationDictionary do - let(:defaults) { {'NAME' => 'Supporter', 'FIRSTNAME' => 'Supporter'}} - let(:sid) { SupporterInterpolationDictionary.new(defaults)} - let(:supporter) { force_create(:supporter)} - let(:supporter_with_empty_name) { force_create(:supporter, name: '')} - let(:supporter_with_whitespace_name) { force_create(:supporter, name: ' ')} - let(:supporter_with_one_word_name) { force_create(:supporter, name: 'penelope')} - let(:supporter_with_two_word_name) { force_create(:supporter, name: 'penelope schultz')} - let(:supporter_with_hyphenated_two_word_name) { force_create(:supporter, name: 'penelope-rebecca schultz')} - describe ".set_supporter" do - it 'makes no changes if supporter passed is not a Supporter' do - sid.set_supporter('') + let(:defaults) { {"NAME" => "Supporter", "FIRSTNAME" => "Supporter"} } + let(:sid) { SupporterInterpolationDictionary.new(defaults) } + let(:supporter) { force_create(:supporter) } + let(:supporter_with_empty_name) { force_create(:supporter, name: "") } + let(:supporter_with_whitespace_name) { force_create(:supporter, name: " ") } + let(:supporter_with_one_word_name) { force_create(:supporter, name: "penelope") } + let(:supporter_with_two_word_name) { force_create(:supporter, name: "penelope schultz") } + let(:supporter_with_hyphenated_two_word_name) { force_create(:supporter, name: "penelope-rebecca schultz") } + describe ".set_supporter" do + it "makes no changes if supporter passed is not a Supporter" do + sid.set_supporter("") expect(sid.entries).to eq(defaults) end - - it 'makes no changes if supporter passed has no name' do + + it "makes no changes if supporter passed has no name" do sid.set_supporter(supporter) expect(sid.entries).to eq(defaults) end - it 'makes no changes if supporter passed has empty name' do + it "makes no changes if supporter passed has empty name" do sid.set_supporter(supporter_with_empty_name) expect(sid.entries).to eq(defaults) end - it 'makes no changes if supporter passed has name with only whitespace' do + it "makes no changes if supporter passed has name with only whitespace" do sid.set_supporter(supporter_with_whitespace_name) expect(sid.entries).to eq(defaults) end - it 'changes if supporter has only one name' do + it "changes if supporter has only one name" do sid.set_supporter(supporter_with_one_word_name) - expect(sid.entries).to eq({'NAME' => 'penelope', 'FIRSTNAME' => 'penelope'}) + expect(sid.entries).to eq({"NAME" => "penelope", "FIRSTNAME" => "penelope"}) end - it 'changes if supporter has two names' do + it "changes if supporter has two names" do sid.set_supporter(supporter_with_two_word_name) - expect(sid.entries).to eq({'NAME' => 'penelope schultz', 'FIRSTNAME' => 'penelope'}) + expect(sid.entries).to eq({"NAME" => "penelope schultz", "FIRSTNAME" => "penelope"}) end - it 'changes if supporter has hyphenated names' do + it "changes if supporter has hyphenated names" do sid.set_supporter(supporter_with_hyphenated_two_word_name) - expect(sid.entries).to eq({'NAME' => 'penelope-rebecca schultz', 'FIRSTNAME' => 'penelope-rebecca'}) + expect(sid.entries).to eq({"NAME" => "penelope-rebecca schultz", "FIRSTNAME" => "penelope-rebecca"}) end end end diff --git a/spec/lib/update/update_charges_spec.rb b/spec/lib/update/update_charges_spec.rb index 6cefbe4c6..3b920689e 100644 --- a/spec/lib/update/update_charges_spec.rb +++ b/spec/lib/update/update_charges_spec.rb @@ -1,43 +1,44 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateCharges do - describe '.disburse_all_with_payments', pending: true do - it 'test' do + describe ".disburse_all_with_payments", pending: true do + it "test" do fail end end - describe '.reverse_disburse_all_with_payments' do + describe ".reverse_disburse_all_with_payments" do let(:payment_to_reverse) { force_create(:payment) } let(:payment_to_ignore) { force_create(:payment) } let(:payment_to_reverse_2) { force_create(:payment) } - let(:payment_to_reverse_with_refund) { force_create(:payment)} - let(:reverse_payment_for_refund) { force_create(:payment)} - let!(:charges) {[force_create(:charge, payment: payment_to_reverse, status: 'disbursed'), - force_create(:charge, payment: payment_to_reverse_2, status: 'disbursed'), - force_create(:charge, payment: payment_to_ignore, status: 'disbursed'), - force_create(:charge, payment: payment_to_reverse_with_refund, status: 'disbursed')]} + let(:payment_to_reverse_with_refund) { force_create(:payment) } + let(:reverse_payment_for_refund) { force_create(:payment) } + let!(:charges) { + [force_create(:charge, payment: payment_to_reverse, status: "disbursed"), + force_create(:charge, payment: payment_to_reverse_2, status: "disbursed"), + force_create(:charge, payment: payment_to_ignore, status: "disbursed"), + force_create(:charge, payment: payment_to_reverse_with_refund, status: "disbursed")] + } - let!(:refunds) { [force_create(:refund, charge: charges.last, payment: reverse_payment_for_refund, disbursed: true)]} + let!(:refunds) { [force_create(:refund, charge: charges.last, payment: reverse_payment_for_refund, disbursed: true)] } before(:each) { UpdateCharges.reverse_disburse_all_with_payments([payment_to_reverse.id, payment_to_reverse_2.id, payment_to_reverse_with_refund.id, reverse_payment_for_refund.id]) } - it 'reverses payments it should' do + it "reverses payments it should" do payment_to_reverse.reload payment_to_reverse_2.reload payment_to_reverse_with_refund.reload - expect(payment_to_reverse.charge.status).to eq 'available' - expect(payment_to_reverse_2.charge.status).to eq 'available' - expect(payment_to_reverse_with_refund.charge.status).to eq 'available' + expect(payment_to_reverse.charge.status).to eq "available" + expect(payment_to_reverse_2.charge.status).to eq "available" + expect(payment_to_reverse_with_refund.charge.status).to eq "available" end - it 'does not reverse other payments' do + it "does not reverse other payments" do payment_to_ignore.reload - expect(payment_to_ignore.charge.status).to eq 'disbursed' + expect(payment_to_ignore.charge.status).to eq "disbursed" end end - -end \ No newline at end of file +end diff --git a/spec/lib/update/update_disputes_spec.rb b/spec/lib/update/update_disputes_spec.rb index 516318df7..01f0a1cd3 100644 --- a/spec/lib/update/update_disputes_spec.rb +++ b/spec/lib/update/update_disputes_spec.rb @@ -1,10 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateDisputes do - describe '.disburse_all_with_payments', pending: true do - it 'test' do + describe ".disburse_all_with_payments", pending: true do + it "test" do fail end end -end \ No newline at end of file +end diff --git a/spec/lib/update/update_donation_spec.rb b/spec/lib/update/update_donation_spec.rb index 8af74622c..fab784d58 100644 --- a/spec/lib/update/update_donation_spec.rb +++ b/spec/lib/update/update_donation_spec.rb @@ -1,8 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateDonation do - before { Timecop.freeze(2020, 2, 3) } @@ -10,66 +9,70 @@ after { Timecop.return } - let(:np) {force_create(:nonprofit)} - let(:supporter) {force_create(:supporter, nonprofit: np)} - let(:donation) {force_create(:donation, nonprofit: np, - dedication: initial_dedication, - comment: initial_comment, - designation: initial_designation, - amount: initial_amount, - date: initial_date, - supporter: supporter)} - - let(:payment) {force_create(:payment, nonprofit: np, donation: donation, - towards: initial_designation, - date: initial_date, - gross_amount: initial_amount, - fee_total: initial_fee, - net_amount: initial_amount - initial_fee, - supporter: supporter, - kind: 'Donation' - )} - let(:offsite_payment) {force_create(:offsite_payment, payment: payment, nonprofit: np, donation: donation, - check_number: initial_check_number, - gross_amount: initial_amount, - date: initial_date, - supporter: supporter)} - - let(:payment2) {force_create(:payment, nonprofit: np, donation: donation, - towards: initial_designation, - date: payment2_date, - gross_amount: initial_amount, - fee_total: initial_fee, - net_amount: initial_amount - initial_fee, kind: 'Donation' - )} - let(:campaign) {force_create(:campaign, nonprofit: np)} - let(:event) {force_create(:event, nonprofit: np)} - let(:other_campaign) {force_create(:campaign)} - let(:other_event) {force_create(:event)} - - let(:initial_date) {Date.new(2020, 4, 5).to_time} - let(:initial_dedication) {"initial dedication"} - let(:initial_comment) {"comment"} - let(:initial_amount) {4000} - let(:initial_designation) {"designation"} - let(:initial_fee) {555} - let(:initial_check_number) {"htoajmioeth"} - - - let(:new_date_input) { '2020-05-05'} - let(:new_date) {Date.new(2020, 5, 5)} - let(:new_dedication) {"new dedication"} - let(:new_comment) {"new comment"} - let(:new_amount) {5646} - let(:new_designation) {"new designation"} - let(:new_fee) {54} - let(:new_check_number) {"new check number"} - - let(:initial_time) {Time.now} - - - let(:payment2_date) {initial_date + 10.days} - let(:activity1) { + let(:np) { force_create(:nonprofit) } + let(:supporter) { force_create(:supporter, nonprofit: np) } + let(:donation) { + force_create(:donation, nonprofit: np, + dedication: initial_dedication, + comment: initial_comment, + designation: initial_designation, + amount: initial_amount, + date: initial_date, + supporter: supporter) + } + + let(:payment) { + force_create(:payment, nonprofit: np, donation: donation, + towards: initial_designation, + date: initial_date, + gross_amount: initial_amount, + fee_total: initial_fee, + net_amount: initial_amount - initial_fee, + supporter: supporter, + kind: "Donation") + } + let(:offsite_payment) { + force_create(:offsite_payment, payment: payment, nonprofit: np, donation: donation, + check_number: initial_check_number, + gross_amount: initial_amount, + date: initial_date, + supporter: supporter) + } + + let(:payment2) { + force_create(:payment, nonprofit: np, donation: donation, + towards: initial_designation, + date: payment2_date, + gross_amount: initial_amount, + fee_total: initial_fee, + net_amount: initial_amount - initial_fee, kind: "Donation") + } + let(:campaign) { force_create(:campaign, nonprofit: np) } + let(:event) { force_create(:event, nonprofit: np) } + let(:other_campaign) { force_create(:campaign) } + let(:other_event) { force_create(:event) } + + let(:initial_date) { Date.new(2020, 4, 5).to_time } + let(:initial_dedication) { "initial dedication" } + let(:initial_comment) { "comment" } + let(:initial_amount) { 4000 } + let(:initial_designation) { "designation" } + let(:initial_fee) { 555 } + let(:initial_check_number) { "htoajmioeth" } + + let(:new_date_input) { "2020-05-05" } + let(:new_date) { Date.new(2020, 5, 5) } + let(:new_dedication) { "new dedication" } + let(:new_comment) { "new comment" } + let(:new_amount) { 5646 } + let(:new_designation) { "new designation" } + let(:new_fee) { 54 } + let(:new_check_number) { "new check number" } + + let(:initial_time) { Time.now } + + let(:payment2_date) { initial_date + 10.days } + let(:activity1) { InsertActivities.for_one_time_donations(payment.id) payment.activities.first } @@ -83,43 +86,48 @@ initial_time payment } - describe '.update_payment' do - describe 'param validation' do - it 'basic validation' do - expect {UpdateDonation.update_payment(nil, nil)}.to raise_error {|error| + describe ".update_payment" do + describe "param validation" do + it "basic validation" do + expect { UpdateDonation.update_payment(nil, nil) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :id, name: :required}, - {key: :id, name: :is_reference}, - {key: :data, name: :required}, - {key: :data, name: :is_hash}]) + {key: :id, name: :is_reference}, + {key: :data, name: :required}, + {key: :data, name: :is_hash}]) } end - it 'validates whether payment is valid' do - expect{ UpdateDonation.update_payment(5555, {})}.to raise_error{|error| + it "validates whether payment is valid" do + expect { UpdateDonation.update_payment(5555, {}) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :id}]) expect(error.message).to eq "5555 is does not correspond to a valid donation" } end - describe 'data validation' do - let(:initial_invalid_arguments) {{ + describe "data validation" do + let(:initial_invalid_arguments) { + { designation: 1, dedication: 1, comment: 1, campaign_id: nil, - event_id: nil}} + event_id: nil + } + } let(:expanded_invalid_arguments) { initial_invalid_arguments.merge({ - fee_total: 'fun', - gross_amount: 'fun', - check_number: Time.now, - date: 'INVALID DATE'}) + fee_total: "fun", + gross_amount: "fun", + check_number: Time.now, + date: "INVALID DATE" + }) } - let(:initial_validation_errors) {[ + let(:initial_validation_errors) { + [ {key: :designation, name: :is_a}, {key: :dedication, name: :is_a}, {key: :comment, name: :is_a}, @@ -127,75 +135,70 @@ {key: :campaign_id, name: :required}, {key: :event_id, name: :is_reference}, {key: :event_id, name: :required} - ]} - it 'for offsite donations' do + ] + } + it "for offsite donations" do offsite_payment activity1 - expect {UpdateDonation.update_payment(donation.id, expanded_invalid_arguments)}.to(raise_error {|error| - + expect { UpdateDonation.update_payment(donation.id, expanded_invalid_arguments) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, initial_validation_errors.concat([ - {key: :fee_total, name: :is_integer}, - {key: :gross_amount, name: :is_integer}, - {key: :gross_amount, name: :min}, - {key: :check_number, name: :is_a}, - {key: :date, name: :can_be_date} - ])) + {key: :fee_total, name: :is_integer}, + {key: :gross_amount, name: :is_integer}, + {key: :gross_amount, name: :min}, + {key: :check_number, name: :is_a}, + {key: :date, name: :can_be_date} + ])) }) end - it 'for online donation' do + it "for online donation" do activity1 - expect {UpdateDonation.update_payment(donation.id, expanded_invalid_arguments)}.to(raise_error {|error| - + expect { UpdateDonation.update_payment(donation.id, expanded_invalid_arguments) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, initial_validation_errors) }) end end - it 'validate campaign_id' do + it "validate campaign_id" do activity1 - expect {UpdateDonation.update_payment(donation.id, {campaign_id: 444, event_id: 444})}.to(raise_error {|error| + expect { UpdateDonation.update_payment(donation.id, {campaign_id: 444, event_id: 444}) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :campaign_id}]) }) end - it 'validate event_id' do + it "validate event_id" do activity1 - expect {UpdateDonation.update_payment(donation.id, {event_id: 4444, campaign_id: campaign.id})}.to(raise_error {|error| + expect { UpdateDonation.update_payment(donation.id, {event_id: 4444, campaign_id: campaign.id}) }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id}]) }) end - it 'validates campaign belongs to payment org' do + it "validates campaign belongs to payment org" do activity1 - campaign_belongs {UpdateDonation.update_payment(donation.id, {campaign_id: other_campaign.id, event_id: event.id})} - + campaign_belongs { UpdateDonation.update_payment(donation.id, {campaign_id: other_campaign.id, event_id: event.id}) } end - it 'validates event belongs to payment org' do + it "validates event belongs to payment org" do activity1 - event_belongs {UpdateDonation.update_payment(donation.id, {event_id: other_event.id, campaign_id:campaign.id})} + event_belongs { UpdateDonation.update_payment(donation.id, {event_id: other_event.id, campaign_id: campaign.id}) } end - - end - describe 'most of the values arent changed if not provided' do - it 'online donation' do + describe "most of the values arent changed if not provided" do + it "online donation" do payment2 activity2 result = verify_nothing_changed(activity2) - - expect(result).to eq (donation.attributes.merge({payment: payment2.attributes})) + expect(result).to eq(donation.attributes.merge({payment: payment2.attributes})) end - it 'offsite donation' do + it "offsite donation" do offsite_payment activity1 result = verify_nothing_changed(activity1) @@ -207,13 +210,12 @@ o_attributes = offsite_payment.attributes offsite_payment.reload expect(o_attributes).to eq offsite_payment.attributes - expect(result).to eq (donation.attributes.merge({payment: payment.attributes, offsite_payment: offsite_payment.attributes})) + expect(result).to eq(donation.attributes.merge({payment: payment.attributes, offsite_payment: offsite_payment.attributes})) end def verify_nothing_changed(activity) a_attributes = activity.attributes - result = UpdateDonation.update_payment(donation.id, {campaign_id: '', event_id: ''}) - + result = UpdateDonation.update_payment(donation.id, {campaign_id: "", event_id: ""}) p_attributes = payment.attributes payment.reload @@ -221,9 +223,8 @@ def verify_nothing_changed(activity) d_attributes = donation.attributes donation.reload - expect(d_attributes).to match donation.attributes.merge({'fts' => an_instance_of(String).or(be_nil)}) + expect(d_attributes).to match donation.attributes.merge({"fts" => an_instance_of(String).or(be_nil)}) - activity.reload expect(a_attributes).to eq activity.attributes @@ -231,25 +232,25 @@ def verify_nothing_changed(activity) end end - describe 'test everything changed' do - let(:new_data) {{designation: new_designation, - dedication: new_dedication, - comment: new_comment, - campaign_id: campaign.id, - event_id: event.id, - - gross_amount: new_amount, - fee_total: new_fee, - check_number: new_check_number, - date: new_date_input - }} - it 'online donation' do + describe "test everything changed" do + let(:new_data) { + {designation: new_designation, + dedication: new_dedication, + comment: new_comment, + campaign_id: campaign.id, + event_id: event.id, + + gross_amount: new_amount, + fee_total: new_fee, + check_number: new_check_number, + date: new_date_input} + } + it "online donation" do payment2 activity2 Timecop.freeze(1.day) do result = UpdateDonation.update_payment(donation.id, new_data) - expected_donation = donation.attributes.merge({designation: new_designation, dedication: new_dedication, comment: new_comment, @@ -264,7 +265,6 @@ def verify_nothing_changed(activity) payment.reload expect(payment.attributes).to eq expected_p1 - expected_p2 = payment2.attributes.merge({towards: new_designation, updated_at: Time.now}).with_indifferent_access payment2.reload @@ -278,46 +278,42 @@ def verify_nothing_changed(activity) activity = activity2 activity.reload expect(activity.date).to eq payment2.date - expect(activity.json_data['gross_amount']).to eq donation.amount - expect(activity.json_data['dedication']).to eq new_dedication - expect(activity.json_data['designation']).to eq new_designation + expect(activity.json_data["gross_amount"]).to eq donation.amount + expect(activity.json_data["dedication"]).to eq new_dedication + expect(activity.json_data["designation"]).to eq new_designation end - - - end - it 'offline donation' do + it "offline donation" do offsite_payment activity1 Timecop.freeze(1.day) do result = UpdateDonation.update_payment(donation.id, new_data) - expected_donation = donation.attributes.merge({ - date: new_date, - amount: new_amount, + date: new_date, + amount: new_amount, - designation: new_designation, - dedication: new_dedication, - comment: new_comment, + designation: new_designation, + dedication: new_dedication, + comment: new_comment, - campaign_id: campaign.id, - event_id: event.id, - updated_at: Time.now, - fts: an_instance_of(String) + campaign_id: campaign.id, + event_id: event.id, + updated_at: Time.now, + fts: an_instance_of(String) }).with_indifferent_access donation.reload expect(donation.attributes).to match expected_donation - expected_p1 = payment.attributes.merge({towards: new_designation, updated_at: Time.now, date: new_date, gross_amount: new_amount, fee_total: new_fee, net_amount: new_amount-new_fee}).with_indifferent_access + expected_p1 = payment.attributes.merge({towards: new_designation, updated_at: Time.now, date: new_date, gross_amount: new_amount, fee_total: new_fee, net_amount: new_amount - new_fee}).with_indifferent_access payment.reload expect(payment.attributes).to eq expected_p1 expect(Payment.count).to eq 1 - expected_offsite_payment= offsite_payment.attributes.merge({check_number:new_check_number, date: new_date.in_time_zone, gross_amount: new_amount, updated_at: Time.now}).with_indifferent_access + expected_offsite_payment = offsite_payment.attributes.merge({check_number: new_check_number, date: new_date.in_time_zone, gross_amount: new_amount, updated_at: Time.now}).with_indifferent_access offsite_payment.reload expect(offsite_payment.attributes).to eq expected_offsite_payment @@ -327,51 +323,49 @@ def verify_nothing_changed(activity) activity = activity1 activity.reload expect(activity.date).to eq payment.date - expect(activity.json_data['gross_amount']).to eq donation.amount - expect(activity.json_data['dedication']).to eq new_dedication - expect(activity.json_data['designation']).to eq new_designation - + expect(activity.json_data["gross_amount"]).to eq donation.amount + expect(activity.json_data["dedication"]).to eq new_dedication + expect(activity.json_data["designation"]).to eq new_designation end end + describe "test blank but existent data will rewrite" do + let(:blank_data) { + {designation: "", + dedication: "", + comment: "", + campaign_id: "", + event_id: "", + + gross_amount: new_amount, + fee_total: new_fee, + check_number: "", + date: new_date_input} + } - describe 'test blank but existent data will rewrite' do - let(:blank_data) {{designation: '', - dedication: '', - comment: '', - campaign_id: '', - event_id: '', - - gross_amount: new_amount, - fee_total: new_fee, - check_number: '', - date: new_date_input - }} - - it 'online donation' do + it "online donation" do payment2 activity2 Timecop.freeze(1.day) do UpdateDonation.update_payment(donation.id, new_data) result = UpdateDonation.update_payment(donation.id, blank_data) - expected_donation = donation.attributes.merge({designation: '', - dedication: '', - comment: '', + expected_donation = donation.attributes.merge({designation: "", + dedication: "", + comment: "", campaign_id: nil, event_id: nil, updated_at: Time.now, - fts: ''}).with_indifferent_access + fts: ""}).with_indifferent_access donation.reload expect(donation.attributes).to eq expected_donation - expected_p1 = payment.attributes.merge({towards: '', updated_at: Time.now}).with_indifferent_access + expected_p1 = payment.attributes.merge({towards: "", updated_at: Time.now}).with_indifferent_access payment.reload expect(payment.attributes).to eq expected_p1 - - expected_p2 = payment2.attributes.merge({towards: '', updated_at: Time.now}).with_indifferent_access + expected_p2 = payment2.attributes.merge({towards: "", updated_at: Time.now}).with_indifferent_access payment2.reload expect(payment2.attributes).to eq expected_p2 @@ -381,18 +375,18 @@ def verify_nothing_changed(activity) expect(offsite_payment.attributes).to eq expected_offsite expect(result).to match create_expected_result(donation, payment2) - + activity = activity2 activity.reload expect(activity.date).to eq payment2.date - - expect(activity.json_data['gross_amount']).to eq donation.amount - expect(activity.json_data['dedication']).to eq donation.dedication - expect(activity.json_data['designation']).to eq donation.designation + + expect(activity.json_data["gross_amount"]).to eq donation.amount + expect(activity.json_data["dedication"]).to eq donation.dedication + expect(activity.json_data["designation"]).to eq donation.designation end end - it 'offline donation' do + it "offline donation" do offsite_payment activity1 Timecop.freeze(1.day) do @@ -400,29 +394,29 @@ def verify_nothing_changed(activity) result = UpdateDonation.update_payment(donation.id, blank_data) expected_donation = donation.attributes.merge({ - date: new_date.in_time_zone, - amount: new_amount, + date: new_date.in_time_zone, + amount: new_amount, - designation: '', - dedication: '', - comment: '', + designation: "", + dedication: "", + comment: "", - campaign_id: nil, - event_id: nil, - updated_at: Time.now, - fts: '' - }).with_indifferent_access + campaign_id: nil, + event_id: nil, + updated_at: Time.now, + fts: "" + }).with_indifferent_access donation.reload expect(donation.attributes).to eq expected_donation - expected_p1 = payment.attributes.merge({towards: '', updated_at: Time.now, date: new_date.in_time_zone, gross_amount: new_amount, fee_total: new_fee, net_amount: new_amount-new_fee}).with_indifferent_access + expected_p1 = payment.attributes.merge({towards: "", updated_at: Time.now, date: new_date.in_time_zone, gross_amount: new_amount, fee_total: new_fee, net_amount: new_amount - new_fee}).with_indifferent_access payment.reload expect(payment.attributes).to eq expected_p1 expect(Payment.count).to eq 1 - expected_offsite_payment= offsite_payment.attributes.merge({check_number:'', date: new_date.in_time_zone, gross_amount: new_amount, updated_at: Time.now}).with_indifferent_access + expected_offsite_payment = offsite_payment.attributes.merge({check_number: "", date: new_date.in_time_zone, gross_amount: new_amount, updated_at: Time.now}).with_indifferent_access offsite_payment.reload expect(offsite_payment.attributes).to eq expected_offsite_payment @@ -431,9 +425,9 @@ def verify_nothing_changed(activity) activity = activity1 activity.reload expect(activity.date).to eq new_date - expect(activity.json_data['gross_amount']).to eq new_amount - expect(activity.json_data['dedication']).to eq '' - expect(activity.json_data['designation']).to eq '' + expect(activity.json_data["gross_amount"]).to eq new_amount + expect(activity.json_data["dedication"]).to eq "" + expect(activity.json_data["designation"]).to eq "" end end end @@ -441,23 +435,23 @@ def verify_nothing_changed(activity) end def event_belongs - expect {yield}.to(raise_error {|error| + expect { yield }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id}]) - expect(error.message).to include 'event does not belong to this nonprofit' + expect(error.message).to include "event does not belong to this nonprofit" }) end def campaign_belongs - expect {yield}.to(raise_error {|error| + expect { yield }.to(raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :campaign_id}]) - expect(error.message).to include 'campaign does not belong to this nonprofit' + expect(error.message).to include "campaign does not belong to this nonprofit" }) end def create_expected_result(donation, payment, offsite_payment = nil) - ret = donation.attributes.merge('fts' => an_instance_of(String)) + ret = donation.attributes.merge("fts" => an_instance_of(String)) ret[:payment] = payment.attributes if offsite_payment ret[:offsite_payment] = offsite_payment.attributes @@ -465,7 +459,4 @@ def create_expected_result(donation, payment, offsite_payment = nil) ret end - end - - diff --git a/spec/lib/update/update_misc_nonprofit_settings_spec.rb b/spec/lib/update/update_misc_nonprofit_settings_spec.rb index 96b959b5f..ed5b91306 100644 --- a/spec/lib/update/update_misc_nonprofit_settings_spec.rb +++ b/spec/lib/update/update_misc_nonprofit_settings_spec.rb @@ -1,55 +1,55 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateMiscellaneousNpInfo do - describe '#update' do - describe 'validates parameters' do - it 'does basic validation' do - expect { UpdateMiscellaneousNpInfo.update(nil, nil)}.to (raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError + describe "#update" do + describe "validates parameters" do + it "does basic validation" do + expect { UpdateMiscellaneousNpInfo.update(nil, nil) }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :np_id, name: :required}, - {key: :np_id, name: :is_integer}, - {key: :misc_settings, name: :required}, - {key: :misc_settings, name: :is_hash}]) + {key: :np_id, name: :is_integer}, + {key: :misc_settings, name: :required}, + {key: :misc_settings, name: :is_hash}]) }) end - it 'does np validation' do - expect { UpdateMiscellaneousNpInfo.update(50, {})}.to (raise_error {|error| - expect(error).to be_a ParamValidation::ValidationError + it "does np validation" do + expect { UpdateMiscellaneousNpInfo.update(50, {}) }.to(raise_error { |error| + expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :np_id}]) }) end end - describe 'main' do - let!(:np){ force_create(:nonprofit)} - let (:working_message) {"

working message

"} - it 'sets change_amount_message to nil if empty tags' do + describe "main" do + let!(:np) { force_create(:nonprofit) } + let(:working_message) { "

working message

" } + it "sets change_amount_message to nil if empty tags" do expect(MiscellaneousNpInfo.count).to eq 0 - update_result = UpdateMiscellaneousNpInfo.update(np.id, {donate_again_url: 'url', not_an_attribute: 3, change_amount_message: "


"}) - expect(update_result).to have_attributes :donate_again_url => 'url', :nonprofit => np, change_amount_message: nil + update_result = UpdateMiscellaneousNpInfo.update(np.id, {donate_again_url: "url", not_an_attribute: 3, change_amount_message: "


"}) + expect(update_result).to have_attributes donate_again_url: "url", nonprofit: np, change_amount_message: nil expect(MiscellaneousNpInfo.count).to eq 1 expect(update_result).to eq MiscellaneousNpInfo.first! end - it 'add misc if it doesnt exist' do + it "add misc if it doesnt exist" do expect(MiscellaneousNpInfo.count).to eq 0 - update_result = UpdateMiscellaneousNpInfo.update(np.id, {donate_again_url: 'url', not_an_attribute: 3, change_amount_message: working_message}) - expect(update_result).to have_attributes :donate_again_url => 'url', :nonprofit => np, change_amount_message: working_message + update_result = UpdateMiscellaneousNpInfo.update(np.id, {donate_again_url: "url", not_an_attribute: 3, change_amount_message: working_message}) + expect(update_result).to have_attributes donate_again_url: "url", nonprofit: np, change_amount_message: working_message expect(MiscellaneousNpInfo.count).to eq 1 expect(update_result).to eq MiscellaneousNpInfo.first! end - it 'update misc if already there' do - Timecop.freeze(2020,01,05) do - old_misc = create(:miscellaneous_np_info, nonprofit: np, donate_again_url: 'old_url') + it "update misc if already there" do + Timecop.freeze(2020, 0o1, 0o5) do + old_misc = create(:miscellaneous_np_info, nonprofit: np, donate_again_url: "old_url") expect(MiscellaneousNpInfo.count).to eq 1 Timecop.freeze(10) do - update_result = UpdateMiscellaneousNpInfo.update(np.id, {donate_again_url: 'url', not_an_attribute: 3, change_amount_message: working_message}) - expect(update_result).to have_attributes :donate_again_url => 'url', :nonprofit => np, change_amount_message: working_message + update_result = UpdateMiscellaneousNpInfo.update(np.id, {donate_again_url: "url", not_an_attribute: 3, change_amount_message: working_message}) + expect(update_result).to have_attributes donate_again_url: "url", nonprofit: np, change_amount_message: working_message expect(MiscellaneousNpInfo.count).to eq 1 expect(update_result).to eq MiscellaneousNpInfo.first! @@ -58,9 +58,6 @@ end end end - - - end end -end \ No newline at end of file +end diff --git a/spec/lib/update/update_payouts_spec.rb b/spec/lib/update/update_payouts_spec.rb index d0ac26cef..0db5ed5f7 100644 --- a/spec/lib/update/update_payouts_spec.rb +++ b/spec/lib/update/update_payouts_spec.rb @@ -1,72 +1,71 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdatePayouts do - describe '.reverse_with_stripe' do - describe 'param validation' do - it 'basic param_validation' do - expect { UpdatePayouts.reverse_with_stripe(nil, nil, nil)}.to(raise_error {|error| + describe ".reverse_with_stripe" do + describe "param validation" do + it "basic param_validation" do + expect { UpdatePayouts.reverse_with_stripe(nil, nil, nil) }.to(raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error.data, [{key: :payout_id, name: :required}, - {key: :payout_id, name: :is_integer}, - {key: :status, name: :required}, - {key: :status, name: :included_in}, - {key: :failure_message, name: :required}, - {key: :failure_message, name: :not_blank}]) + {key: :payout_id, name: :is_integer}, + {key: :status, name: :required}, + {key: :status, name: :included_in}, + {key: :failure_message, name: :required}, + {key: :failure_message, name: :not_blank}]) }) end - it 'reject non-existent payouts' do - expect { UpdatePayouts.reverse_with_stripe(5555555, "failed", "failure")}.to(raise_error {|error| + it "reject non-existent payouts" do + expect { UpdatePayouts.reverse_with_stripe(5555555, "failed", "failure") }.to(raise_error { |error| expect(error).to be_a(ParamValidation::ValidationError) expect_validation_errors(error.data, [{key: :payout_id}]) }) end - it 'reject payouts with no payments' do + it "reject payouts with no payments" do payout = force_create(:payout) - expect { UpdatePayouts.reverse_with_stripe(payout.id, "failed", "failure")}.to(raise_error {|error| + expect { UpdatePayouts.reverse_with_stripe(payout.id, "failed", "failure") }.to(raise_error { |error| expect(error).to be_a(ArgumentError) }) end - - end - describe 'validate proper function' do + describe "validate proper function" do let(:payment_to_reverse) { force_create(:payment) } let(:payment_to_ignore) { force_create(:payment) } let(:payment_to_reverse_2) { force_create(:payment) } - let(:payment_to_reverse_with_refund) { force_create(:payment)} - let(:reverse_payment_for_refund) { force_create(:payment)} - let(:payment_for_disputed_charge) {force_create(:payment)} - - let(:payment_for_dispute_transaction) {force_create(:payment)} + let(:payment_to_reverse_with_refund) { force_create(:payment) } + let(:reverse_payment_for_refund) { force_create(:payment) } + let(:payment_for_disputed_charge) { force_create(:payment) } + let(:payment_for_dispute_transaction) { force_create(:payment) } - let!(:charges) {[force_create(:charge, payment: payment_to_reverse, status: 'disbursed'), - force_create(:charge, payment: payment_to_reverse_2, status: 'disbursed'), - force_create(:charge, payment: payment_to_ignore, status: 'disbursed'), - force_create(:charge, payment: payment_to_reverse_with_refund, status:'disbursed'), + let!(:charges) { + [force_create(:charge, payment: payment_to_reverse, status: "disbursed"), + force_create(:charge, payment: payment_to_reverse_2, status: "disbursed"), + force_create(:charge, payment: payment_to_ignore, status: "disbursed"), + force_create(:charge, payment: payment_to_reverse_with_refund, status: "disbursed"), - force_create(:charge, payment: payment_for_disputed_charge, status:'disbursed') - ]} - - let!(:refunds) { [force_create(:refund, charge: charges[-2], payment: reverse_payment_for_refund, disbursed: true)]} + force_create(:charge, payment: payment_for_disputed_charge, status: "disbursed")] + } - let!(:disputes) { [create(:dispute, charge: charges.last, dispute_transactions:[build(:dispute_transaction, payment: payment_for_dispute_transaction, disbursed:true)])]} + let!(:refunds) { [force_create(:refund, charge: charges[-2], payment: reverse_payment_for_refund, disbursed: true)] } + let!(:disputes) { [create(:dispute, charge: charges.last, dispute_transactions: [build(:dispute_transaction, payment: payment_for_dispute_transaction, disbursed: true)])] } - let(:np) {force_create(:nonprofit)} - let!(:bank_account) {force_create(:bank_account, nonprofit: np)} - let!(:payout) {force_create(:payout, status: "paid", failure_message: 'all good', - nonprofit: np, stripe_transfer_id: 'transfer_id', email: 'no one cares', net_amount: 500)} + let(:np) { force_create(:nonprofit) } + let!(:bank_account) { force_create(:bank_account, nonprofit: np) } + let!(:payout) { + force_create(:payout, status: "paid", failure_message: "all good", + nonprofit: np, stripe_transfer_id: "transfer_id", email: "no one cares", net_amount: 500) + } - let(:bad_status) { 'failed'} - let(:bad_failure_message) { 'so terrible'} - let(:available) { 'available'} + let(:bad_status) { "failed" } + let(:bad_failure_message) { "so terrible" } + let(:available) { "available" } - before(:each){ + before(:each) { payout.payments.push(payment_to_reverse) payout.payments.push(payment_to_reverse_2) payout.payments.push(payment_to_reverse_with_refund) @@ -75,7 +74,7 @@ UpdatePayouts.reverse_with_stripe(payout.id, bad_status, bad_failure_message) } - it 'reverses proper payments' do + it "reverses proper payments" do payment_to_reverse.reload payment_to_reverse_2.reload payment_to_reverse_with_refund.reload @@ -84,13 +83,13 @@ expect(payment_to_reverse_with_refund.charge.status).to eq available end - it 'reverses proper refunds' do + it "reverses proper refunds" do refund = refunds.first refund.reload expect(refund.disbursed).to eq false end - it 'reverses disputes' do + it "reverses disputes" do payment_for_dispute_transaction.reload disputes.first.reload disputes.first.dispute_transactions.first.reload @@ -99,15 +98,15 @@ expect(dispute_trx).to_not be_disbursed end - it 'ignores irrelevant payments' do - expect(payment_to_ignore.charge.status).to eq 'disbursed' + it "ignores irrelevant payments" do + expect(payment_to_ignore.charge.status).to eq "disbursed" end - it 'changes payout status and failure' do + it "changes payout status and failure" do payout.reload expect(payout.status).to eq bad_status expect(payout.failure_message).to eq bad_failure_message end end end -end \ No newline at end of file +end diff --git a/spec/lib/update/update_recurring_donations_spec.rb b/spec/lib/update/update_recurring_donations_spec.rb index 4baf352ad..eedf099b4 100644 --- a/spec/lib/update/update_recurring_donations_spec.rb +++ b/spec/lib/update/update_recurring_donations_spec.rb @@ -1,107 +1,102 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateRecurringDonations do - let!(:automated_user) { create(:automated_user)} + let!(:automated_user) { create(:automated_user) } # deactivate a recurring donation - describe '.cancel' do - - let(:np) { force_create(:nonprofit)} - let(:s) { force_create(:supporter)} - let(:donation) {create(:donation, nonprofit_id: np.id, supporter_id: s.id, amount: 999)} - let(:email) {'test@test.com' } + describe ".cancel" do + let(:np) { force_create(:nonprofit) } + let(:s) { force_create(:supporter) } + let(:donation) { create(:donation, nonprofit_id: np.id, supporter_id: s.id, amount: 999) } + let(:email) { "test@test.com" } let!(:rd) { - inner_rd = create(:recurring_donation_base, amount:999, active:true, supporter_id: s.id, donation_id: donation.id, nonprofit_id: np.id) - UpdateRecurringDonations.cancel(inner_rd.id, email)} - + inner_rd = create(:recurring_donation_base, amount: 999, active: true, supporter_id: s.id, donation_id: donation.id, nonprofit_id: np.id) + UpdateRecurringDonations.cancel(inner_rd.id, email) + } - it 'sets active to false' do - expect(rd['active']).to eq false + it "sets active to false" do + expect(rd["active"]).to eq false end - it 'sets cancelled_at to today' do - expect(rd['cancelled_at'].end_of_day).to eq(Time.current.end_of_day) + it "sets cancelled_at to today" do + expect(rd["cancelled_at"].end_of_day).to eq(Time.current.end_of_day) end - it 'sets the cancelled_by to the given email' do - expect(rd['cancelled_by']).to eq email + it "sets the cancelled_by to the given email" do + expect(rd["cancelled_by"]).to eq email end - it 'returns the full fetch_for_edit data' do - expect(rd['nonprofit_name']).to eq np.name + it "returns the full fetch_for_edit data" do + expect(rd["nonprofit_name"]).to eq np.name end - it 'creates a supporter note table describing the cancellation' do - note = Qx.select(:content).from(:supporter_notes).limit(1).order_by('id DESC').execute.first - expect(note['content']).to include("cancelled") + it "creates a supporter note table describing the cancellation" do + note = Qx.select(:content).from(:supporter_notes).limit(1).order_by("id DESC").execute.first + expect(note["content"]).to include("cancelled") end end - describe '.update_amount' do - + describe ".update_amount" do include_context :shared_rd_donation_value_context - describe 'param validation' do - it 'rejects totally invalid data' do - expect { UpdateRecurringDonations.update_amount(nil, nil, nil)} + describe "param validation" do + it "rejects totally invalid data" do + expect { UpdateRecurringDonations.update_amount(nil, nil, nil) } .to(raise_error do |error| expect(error).to be_a ParamValidation::ValidationError - expect_validation_errors(error,[{key: 'rd', name: :required}, - {key: 'rd', name: :is_a}, - {key: :token, name: :required}, - {key: :token, name: :format}, - {key: 'amount', name: :required}, - {key: 'amount', name: :is_integer}, - {key: 'amount', name: :min}]) + expect_validation_errors(error, [{key: "rd", name: :required}, + {key: "rd", name: :is_a}, + {key: :token, name: :required}, + {key: :token, name: :format}, + {key: "amount", name: :required}, + {key: "amount", name: :is_integer}, + {key: "amount", name: :min}]) end) end - end - describe 'token validation' do - it 'invalid token errors' do - validation_invalid_token {UpdateRecurringDonations.update_amount(recurring_donation, fake_uuid, 500)} + describe "token validation" do + it "invalid token errors" do + validation_invalid_token { UpdateRecurringDonations.update_amount(recurring_donation, fake_uuid, 500) } end - it 'unauthorized token errors' do - validation_unauthorized {UpdateRecurringDonations.update_amount(recurring_donation, fake_uuid, 500)} + it "unauthorized token errors" do + validation_unauthorized { UpdateRecurringDonations.update_amount(recurring_donation, fake_uuid, 500) } end - it 'validation expired errors' do - validation_expired { UpdateRecurringDonations.update_amount(recurring_donation, fake_uuid, 500)} + it "validation expired errors" do + validation_expired { UpdateRecurringDonations.update_amount(recurring_donation, fake_uuid, 500) } end end - describe 'validate entities' do - it 'errors when rd is cancelled' do - error_when_rd_cancelled {UpdateRecurringDonations.update_amount(recurring_donation, source_token.id, 500)} + describe "validate entities" do + it "errors when rd is cancelled" do + error_when_rd_cancelled { UpdateRecurringDonations.update_amount(recurring_donation, source_token.id, 500) } end - it 'errors when card is deleted' do - error_when_card_deleted {UpdateRecurringDonations.update_amount( recurring_donation, source_token.id, 500)} + it "errors when card is deleted" do + error_when_card_deleted { UpdateRecurringDonations.update_amount(recurring_donation, source_token.id, 500) } end - it 'errors when card holder and supporter arent the same' do - errors_when_card_holder_and_supporter_neq { UpdateRecurringDonations.update_amount( recurring_donation, other_source_token.id, 500)} + it "errors when card holder and supporter arent the same" do + errors_when_card_holder_and_supporter_neq { UpdateRecurringDonations.update_amount(recurring_donation, other_source_token.id, 500) } end end - it 'changes amount properly' do - + it "changes amount properly" do recurring_donation.n_failures = 2 recurring_donation.save! orig_rd = recurring_donation.attributes.with_indifferent_access orig_donation = recurring_donation.donation.attributes.with_indifferent_access - - expect_job_queued.with(JobTypes::DonorRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd['amount']) - expect_job_queued.with(JobTypes::NonprofitRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd['amount']) + expect_job_queued.with(JobTypes::DonorRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd["amount"]) + expect_job_queued.with(JobTypes::NonprofitRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd["amount"]) result = UpdateRecurringDonations.update_amount(recurring_donation, source_token.token, 1000) expectations = { - donation: orig_donation.merge(amount: 1000, card_id: source_token.tokenizable.id, fts: ""), - recurring_donation: orig_rd.merge(amount: 1000, n_failures: 0, start_date: Time.current.to_date) + donation: orig_donation.merge(amount: 1000, card_id: source_token.tokenizable.id, fts: ""), + recurring_donation: orig_rd.merge(amount: 1000, n_failures: 0, start_date: Time.current.to_date) } expect(result.attributes).to eq expectations[:recurring_donation] @@ -109,28 +104,27 @@ recurring_donation.reload donation_for_rd.reload - expect(recurring_donation.attributes).to eq expectations[:recurring_donation] + expect(recurring_donation.attributes).to eq expectations[:recurring_donation] expect(donation_for_rd.attributes).to eq expectations[:donation] expect(recurring_donation.misc_recurring_donation_info.fee_covered).to eq false end - it 'changes amount properly and marks as fee_covered' do - + it "changes amount properly and marks as fee_covered" do recurring_donation.n_failures = 2 recurring_donation.save! orig_rd = recurring_donation.attributes.with_indifferent_access orig_donation = recurring_donation.donation.attributes.with_indifferent_access - expect_job_queued.with(JobTypes::DonorRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd['amount']) - expect_job_queued.with(JobTypes::NonprofitRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd['amount']) + expect_job_queued.with(JobTypes::DonorRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd["amount"]) + expect_job_queued.with(JobTypes::NonprofitRecurringDonationChangeAmountJob, recurring_donation.id, orig_rd["amount"]) result = UpdateRecurringDonations.update_amount(recurring_donation, source_token.token, 1000, true) expectations = { - donation: orig_donation.merge(amount: 1000, card_id: source_token.tokenizable.id, fts: ""), - recurring_donation: orig_rd.merge(amount: 1000, n_failures: 0, start_date: Time.current.to_date) + donation: orig_donation.merge(amount: 1000, card_id: source_token.tokenizable.id, fts: ""), + recurring_donation: orig_rd.merge(amount: 1000, n_failures: 0, start_date: Time.current.to_date) } expect(result.attributes).to eq expectations[:recurring_donation] @@ -138,62 +132,60 @@ recurring_donation.reload donation_for_rd.reload - expect(recurring_donation.attributes).to eq expectations[:recurring_donation] + expect(recurring_donation.attributes).to eq expectations[:recurring_donation] expect(recurring_donation.misc_recurring_donation_info.fee_covered).to eq true expect(donation_for_rd.attributes).to eq expectations[:donation] end end - describe '.update_card_id' do + describe ".update_card_id" do include_context :shared_rd_donation_value_context - describe 'basic validation' do - it 'basic param validation' do - expect { UpdateRecurringDonations.update_card_id(nil, nil)}.to raise_error{|e| + describe "basic validation" do + it "basic param validation" do + expect { UpdateRecurringDonations.update_card_id(nil, nil) }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [ - {key: :rd, name: :is_hash}, - {key: :rd, name: :required}, - {key: :token, name: :required}, - {key: :token, name: :format} + {key: :rd, name: :is_hash}, + {key: :rd, name: :required}, + {key: :token, name: :required}, + {key: :token, name: :format} ]) } end - it 'rd[:id] validation' do - expect { UpdateRecurringDonations.update_card_id({}, fake_uuid)}.to raise_error{|e| + it "rd[:id] validation" do + expect { UpdateRecurringDonations.update_card_id({}, fake_uuid) }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [ - {key: :id, name: :is_reference}, - {key: :id, name: :required}, + {key: :id, name: :is_reference}, + {key: :id, name: :required} ]) } end end - describe 'token validation' do - it 'invalid token errors' do - validation_invalid_token {UpdateRecurringDonations.update_card_id({id: 555}, fake_uuid)} + describe "token validation" do + it "invalid token errors" do + validation_invalid_token { UpdateRecurringDonations.update_card_id({id: 555}, fake_uuid) } end - it 'unauthorized token errors' do - validation_unauthorized {UpdateRecurringDonations.update_card_id({id: 555}, fake_uuid)} + it "unauthorized token errors" do + validation_unauthorized { UpdateRecurringDonations.update_card_id({id: 555}, fake_uuid) } end - it 'validation expired errors' do - validation_expired { UpdateRecurringDonations.update_card_id({id: 555}, fake_uuid)} + it "validation expired errors" do + validation_expired { UpdateRecurringDonations.update_card_id({id: 555}, fake_uuid) } end end - describe 'entity retrieval errors' do - it 'find error on recurring donation' do - find_error_recurring_donation { UpdateRecurringDonations.update_card_id({id: 55555}, source_token.token)} + describe "entity retrieval errors" do + it "find error on recurring donation" do + find_error_recurring_donation { UpdateRecurringDonations.update_card_id({id: 55555}, source_token.token) } end end - - - it 'finishes properly' do + it "finishes properly" do recurring_donation.n_failures = 2 recurring_donation.save! orig_rd = recurring_donation.attributes.with_indifferent_access @@ -202,9 +194,8 @@ result = UpdateRecurringDonations.update_card_id({id: recurring_donation.id}, source_token.token) expectations = { - - donation: orig_donation.merge(card_id: card.id, fts: ""), - recurring_donation: orig_rd.merge(n_failures: 0, start_date: Time.now.to_date), + donation: orig_donation.merge(card_id: card.id, fts: ""), + recurring_donation: orig_rd.merge(n_failures: 0, start_date: Time.now.to_date) } expectations[:result] = expectations[:recurring_donation].merge(nonprofit_name: nonprofit.name, card_name: card.name) @@ -219,7 +210,7 @@ end def find_error_recurring_donation - expect {yield()}.to raise_error {|e| + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :id}]) } @@ -229,8 +220,7 @@ def error_when_rd_cancelled recurring_donation.cancelled_at = Time.now recurring_donation.save! - expect {yield()}.to raise_error{|e| - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :id}]) expect(e.message).to eq "Recurring Donation #{recurring_donation.id} is already cancelled." @@ -241,8 +231,7 @@ def error_when_card_deleted card.deleted = true card.save! - expect {yield()}.to raise_error{|e| - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :token}]) expect(e.message).to eq "Tokenized card #{card.id} is not valid." @@ -250,12 +239,10 @@ def error_when_card_deleted end def errors_when_card_holder_and_supporter_neq - expect {yield()}.to raise_error{|e| - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :token}]) expect(e.message).to eq "Supporter #{supporter.id} does not own card #{other_source_token.tokenizable.id}" } end - end diff --git a/spec/lib/update/update_refunds_spec.rb b/spec/lib/update/update_refunds_spec.rb index 8ff370e95..09a08650c 100644 --- a/spec/lib/update/update_refunds_spec.rb +++ b/spec/lib/update/update_refunds_spec.rb @@ -1,33 +1,34 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateRefunds do - describe '.disburse_all_with_payments', pending: true do - it 'test' do + describe ".disburse_all_with_payments", pending: true do + it "test" do fail end end - describe '.reverse_disburse_all_with_payments' do - + describe ".reverse_disburse_all_with_payments" do let(:payment_to_reverse) { force_create(:payment) } - let(:payment_to_ignore) {force_create(:payment)} - let!(:refunds) { [ - force_create(:refund, payment: payment_to_reverse, disbursed:true), - force_create(:refund, payment:payment_to_ignore, disbursed:true) - ]} + let(:payment_to_ignore) { force_create(:payment) } + let!(:refunds) { + [ + force_create(:refund, payment: payment_to_reverse, disbursed: true), + force_create(:refund, payment: payment_to_ignore, disbursed: true) + ] + } before(:each) { UpdateRefunds.reverse_disburse_all_with_payments([payment_to_reverse.id]) - refunds.each{|i| i.reload} + refunds.each { |i| i.reload } } - it 'reverses refunds as it should' do + it "reverses refunds as it should" do expect(refunds.first.disbursed).to eq false end - it 'doesn\'t reverse unselected refund' do + it "doesn't reverse unselected refund" do expect(refunds.last.disbursed).to eq true end end -end \ No newline at end of file +end diff --git a/spec/lib/update/update_supporter_spec.rb b/spec/lib/update/update_supporter_spec.rb index 1cd6b4f1b..bf076ffc7 100644 --- a/spec/lib/update/update_supporter_spec.rb +++ b/spec/lib/update/update_supporter_spec.rb @@ -1,7 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - -describe UpdateSupporter, pending:true do +require "rails_helper" +describe UpdateSupporter, pending: true do end - diff --git a/spec/lib/update/update_tickets_spec.rb b/spec/lib/update/update_tickets_spec.rb index d2b5e5261..7abf3ca81 100644 --- a/spec/lib/update/update_tickets_spec.rb +++ b/spec/lib/update/update_tickets_spec.rb @@ -1,16 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe UpdateTickets do - - let(:ticket) { - Event.any_instance.stub(:geocode).and_return([1,1]) + Event.any_instance.stub(:geocode).and_return([1, 1]) create(:ticket, :has_card, :has_event) } - - describe '.update' do + describe ".update" do include_context :shared_rd_donation_value_context let(:basic_valid_ticket_input) { @@ -26,162 +23,152 @@ let(:general_ticket) { { - quantity: 1, - supporter: supporter, - payment: payment, - charge: charge, - event_discount: event_discount, - created_at: Time.now, - updated_at: Time.now, - checked_in: nil, - bid_id: 1, - card_id: nil, - profile_id: nil, - note: nil, - deleted: false, - source_token_id: nil, - ticket_level_id: nil + quantity: 1, + supporter: supporter, + payment: payment, + charge: charge, + event_discount: event_discount, + created_at: Time.now, + updated_at: Time.now, + checked_in: nil, + bid_id: 1, + card_id: nil, + profile_id: nil, + note: nil, + deleted: false, + source_token_id: nil, + ticket_level_id: nil } } let(:general_expected) { { - id: ticket.id, - quantity: 1, - supporter_id: supporter.id, - payment_id: payment.id, - charge_id: charge.id, - event_discount_id: event_discount.id, - created_at: Time.now, - updated_at: Time.now, - checked_in: nil, - bid_id: 1, - card_id: nil, - profile_id: nil, - note: nil, - deleted: false, - source_token_id: nil, - event_id: event.id, - ticket_level_id: nil, - ticket_purchase_id: nil + id: ticket.id, + quantity: 1, + supporter_id: supporter.id, + payment_id: payment.id, + charge_id: charge.id, + event_discount_id: event_discount.id, + created_at: Time.now, + updated_at: Time.now, + checked_in: nil, + bid_id: 1, + card_id: nil, + profile_id: nil, + note: nil, + deleted: false, + source_token_id: nil, + event_id: event.id, + ticket_level_id: nil, + ticket_purchase_id: nil }.with_indifferent_access } - let(:payment) {force_create(:payment)} - let(:charge) {force_create(:charge)} - - let(:ticket) {force_create(:ticket, - general_ticket.merge(event: event) )} + let(:payment) { force_create(:payment) } + let(:charge) { force_create(:charge) } - let(:other_ticket) {force_create(:ticket, - general_ticket.merge(event: other_event ))} + let(:ticket) { + force_create(:ticket, + general_ticket.merge(event: event)) + } - it 'basic validation' do - expect {UpdateTickets.update(token: "bhaetiwhet", checked_in: 'blah', bid_id: 'bhalehti') }.to raise_error {|error| + let(:other_ticket) { + force_create(:ticket, + general_ticket.merge(event: other_event)) + } + it "basic validation" do + expect { UpdateTickets.update(token: "bhaetiwhet", checked_in: "blah", bid_id: "bhalehti") }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [ - {key: :event_id, name: :required}, - {key: :event_id, name: :is_reference}, - {key: :ticket_id, name: :required}, - {key: :ticket_id, name: :is_reference}, - {key: :token, name: :format}, - {key: :bid_id, name: :is_integer}, - {key: :checked_in, name: :included_in} + {key: :event_id, name: :required}, + {key: :event_id, name: :is_reference}, + {key: :ticket_id, name: :required}, + {key: :ticket_id, name: :is_reference}, + {key: :token, name: :format}, + {key: :bid_id, name: :is_integer}, + {key: :checked_in, name: :included_in} ]) } end - it 'event is invalid' do - find_error_event {UpdateTickets.update( event_id: 5555, ticket_id: ticket.id)} + it "event is invalid" do + find_error_event { UpdateTickets.update(event_id: 5555, ticket_id: ticket.id) } end - it 'ticket is invalid' do - find_error_ticket {UpdateTickets.update( event_id: event.id, ticket_id: 5555)} + it "ticket is invalid" do + find_error_ticket { UpdateTickets.update(event_id: event.id, ticket_id: 5555) } end - it 'ticket is deleted' do + it "ticket is deleted" do ticket.deleted = true ticket.save! - expect {UpdateTickets.update( event_id: event.id, ticket_id: ticket.id)}.to raise_error {|error| - + expect { UpdateTickets.update(event_id: event.id, ticket_id: ticket.id) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :ticket_id}]) - expect(error.message).to include 'deleted' + expect(error.message).to include "deleted" expect(error.message).to include "Ticket ID #{ticket.id}" } end - it 'event is deleted' do + it "event is deleted" do event.deleted = true event.save! - expect {UpdateTickets.update( event_id: event.id, ticket_id: ticket.id)}.to raise_error {|error| - + expect { UpdateTickets.update(event_id: event.id, ticket_id: ticket.id) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id}]) - expect(error.message).to include 'deleted' + expect(error.message).to include "deleted" expect(error.message).to include "Event ID #{event.id}" } end - it 'event and ticket dont match' do - - - expect {UpdateTickets.update( event_id: event.id, ticket_id: other_ticket.id)}.to raise_error {|error| - + it "event and ticket dont match" do + expect { UpdateTickets.update(event_id: event.id, ticket_id: other_ticket.id) }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :ticket_id}]) expect(error.message).to include "Ticket ID #{other_ticket.id} does not belong to event #{event.id}" } end - it 'token is invalid' do - - validation_invalid_token {UpdateTickets.update(include_fake_token)} - + it "token is invalid" do + validation_invalid_token { UpdateTickets.update(include_fake_token) } end - it 'errors out if token is unauthorized' do - - validation_unauthorized {UpdateTickets.update(include_fake_token)} - + it "errors out if token is unauthorized" do + validation_unauthorized { UpdateTickets.update(include_fake_token) } end - it 'errors out if token is expired' do - - validation_expired {UpdateTickets.update(include_fake_token)} - + it "errors out if token is expired" do + validation_expired { UpdateTickets.update(include_fake_token) } end - it 'card doesnt belong to supporter' do - - validation_card_not_with_supporter {UpdateTickets.update(include_fake_token.merge({ token: other_source_token.token}))} - + it "card doesnt belong to supporter" do + validation_card_not_with_supporter { UpdateTickets.update(include_fake_token.merge({token: other_source_token.token})) } end - it 'success editing note' do - result = UpdateTickets.update(basic_valid_ticket_input.merge(note:'noteedited')) - expected = general_expected.merge(note:'noteedited') + it "success editing note" do + result = UpdateTickets.update(basic_valid_ticket_input.merge(note: "noteedited")) + expected = general_expected.merge(note: "noteedited") expect(result.attributes).to eq expected ticket.reload expect(ticket.attributes).to eq expected end - it 'success editing bid_id' do - result = UpdateTickets.update(basic_valid_ticket_input.merge(bid_id:50)) - expected = general_expected.merge(bid_id:50) + it "success editing bid_id" do + result = UpdateTickets.update(basic_valid_ticket_input.merge(bid_id: 50)) + expected = general_expected.merge(bid_id: 50) expect(result.attributes).to eq expected ticket.reload expect(ticket.attributes).to eq expected end - it 'success editing checked_in' do - result = UpdateTickets.update(basic_valid_ticket_input.merge(checked_in:'true')) + it "success editing checked_in" do + result = UpdateTickets.update(basic_valid_ticket_input.merge(checked_in: "true")) expected = general_expected.merge(checked_in: true) expect(result.attributes).to eq expected @@ -189,8 +176,8 @@ expect(ticket.attributes).to eq expected end - it 'success editing checked_in as a boolean' do - result = UpdateTickets.update(basic_valid_ticket_input.merge(checked_in:true)) + it "success editing checked_in as a boolean" do + result = UpdateTickets.update(basic_valid_ticket_input.merge(checked_in: true)) expected = general_expected.merge(checked_in: true) expect(result.attributes).to eq expected @@ -198,8 +185,8 @@ expect(ticket.attributes).to eq expected end - it 'success editing token' do - result = UpdateTickets.update(basic_valid_ticket_input.merge(token:source_token.token)) + it "success editing token" do + result = UpdateTickets.update(basic_valid_ticket_input.merge(token: source_token.token)) expected = general_expected.merge(source_token_id: source_token.id) expect(result.attributes).to eq expected @@ -208,35 +195,34 @@ end end - describe '.delete' do + describe ".delete" do around(:each) do |ex| StripeMockHelper.mock do ex.run end end - it 'marks the given ticket as deleted=true' do - UpdateTickets.delete(ticket['event_id'], ticket['id']) + it "marks the given ticket as deleted=true" do + UpdateTickets.delete(ticket["event_id"], ticket["id"]) ticket.reload - expect(ticket['deleted']).to eq(true) + expect(ticket["deleted"]).to eq(true) expect(Ticket.count).to eq(1) end end - describe '.delete_card_for_ticket' do + describe ".delete_card_for_ticket" do around(:each) do |ex| - StripeMockHelper.mock do + StripeMockHelper.mock do ex.run end end - it 'deletes the card from the ticket' do + it "deletes the card from the ticket" do Timecop.freeze(2020, 1, 5) do - original_ticket = ticket card = ticket.card expect(ticket.card).to_not be_nil - ret = UpdateTickets.delete_card_for_ticket(ticket['event_id'], ticket['id']) + ret = UpdateTickets.delete_card_for_ticket(ticket["event_id"], ticket["id"]) expect(ret[:status]).to eq :ok expect(ret[:json]).to eq({}) ticket.reload @@ -244,28 +230,27 @@ expect(ticket.card).to be_nil expect(Ticket.count).to eq(1) skip_attribs = [:updated_at, :card] - expect(ticket.attributes.select{|k,_| !skip_attribs.include?(k)}).to eq original_ticket.attributes.select{|k, _| !skip_attribs.include?(k)} + expect(ticket.attributes.select { |k, _| !skip_attribs.include?(k) }).to eq original_ticket.attributes.select { |k, _| !skip_attribs.include?(k) } expect(ticket.updated_at).to eq Time.now end end - context 'parameter validation' do - it 'validates parameters' do - + context "parameter validation" do + it "validates parameters" do result = UpdateTickets.delete_card_for_ticket(nil, nil) errors = result[:json][:errors] expect(errors.length).to eq(4) expect(result[:status]).to eq :unprocessable_entity expect_validation_errors(errors, [ - {key: :event_id, name: :required}, - {key: :event_id, name: :is_integer}, - {key: :ticket_id, name: :required}, - {key: :ticket_id, name: :is_integer} + {key: :event_id, name: :required}, + {key: :event_id, name: :is_integer}, + {key: :ticket_id, name: :required}, + {key: :ticket_id, name: :is_integer} ]) end - it 'invalid event_id causes no problem' do + it "invalid event_id causes no problem" do ticket tickets = Ticket.all events = Event.all @@ -275,7 +260,7 @@ expect(Event.all).to match_array(events) end - it 'invalid ticket_id causes no problem' do + it "invalid ticket_id causes no problem" do ticket tickets = Ticket.all events = Event.all @@ -285,6 +270,5 @@ expect(Event.all).to match_array(events) end end - end end diff --git a/spec/lib/uuid_spec.rb b/spec/lib/uuid_spec.rb index 31e7d43c1..2d4dd08e5 100644 --- a/spec/lib/uuid_spec.rb +++ b/spec/lib/uuid_spec.rb @@ -1,26 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'securerandom' -require_relative '../../app/legacy_lib/uuid' +require "securerandom" +require_relative "../../app/legacy_lib/uuid" describe UUID do - describe '::Regex' do - it 'rejects nil' do + describe "::Regex" do + it "rejects nil" do expect(nil).to_not match(UUID::Regex) end - it 'rejects blank' do - expect('').to_not match(UUID::Regex) + it "rejects blank" do + expect("").to_not match(UUID::Regex) end - it 'rejects non-uuid string' do - expect('thweoihchnao-n r -fahc').to_not match(UUID::Regex) + it "rejects non-uuid string" do + expect("thweoihchnao-n r -fahc").to_not match(UUID::Regex) end - it 'accepts unbraced uuid' do + it "accepts unbraced uuid" do expect(SecureRandom.uuid).to match(UUID::Regex) end - it 'accepts braced uuid' do + it "accepts braced uuid" do expect("{#{SecureRandom.uuid}}").to match(UUID::Regex) end end diff --git a/spec/mailers/admin_spec.rb b/spec/mailers/admin_spec.rb index 88dffa491..5707728be 100644 --- a/spec/mailers/admin_spec.rb +++ b/spec/mailers/admin_spec.rb @@ -1,22 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -RSpec.describe AdminMailer, :type => :mailer do +RSpec.describe AdminMailer, type: :mailer do describe "notify_failed_gift" do around(:each) do |ex| - StripeMockHelper.mock do + StripeMockHelper.mock do ex.run end end - let!(:np) { force_create(:nonprofit, name: "nonprofit", email: 'blah', timezone: "UTC")} - let!(:s) { force_create(:supporter, email: 'supporter.email@mail.teha')} - let!(:oldcard) { force_create(:card)} - let!(:payment) { force_create(:payment, donation_id: donation.id, nonprofit_id:np.id, supporter_id: s.id, gross_amount: 999)} - let!(:donation) {force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999)} - let!(:charge) { create(:charge, :donation => donation, :nonprofit => np, amount: 100, created_at: Time.now)} - let(:campaign) {force_create(:campaign, nonprofit: np)} - let!(:campaign_gift_option_with_desc) {force_create(:campaign_gift_option, description: 'desc', amount_one_time: '', campaign: campaign)} - let!(:campaign_gift_option) {force_create(:campaign_gift_option, campaign: campaign)} + let!(:np) { force_create(:nonprofit, name: "nonprofit", email: "blah", timezone: "UTC") } + let!(:s) { force_create(:supporter, email: "supporter.email@mail.teha") } + let!(:oldcard) { force_create(:card) } + let!(:payment) { force_create(:payment, donation_id: donation.id, nonprofit_id: np.id, supporter_id: s.id, gross_amount: 999) } + let!(:donation) { force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999) } + let!(:charge) { create(:charge, donation: donation, nonprofit: np, amount: 100, created_at: Time.now) } + let(:campaign) { force_create(:campaign, nonprofit: np) } + let!(:campaign_gift_option_with_desc) { force_create(:campaign_gift_option, description: "desc", amount_one_time: "", campaign: campaign) } + let!(:campaign_gift_option) { force_create(:campaign_gift_option, campaign: campaign) } let(:mail) { AdminMailer.notify_failed_gift(donation, payment, campaign_gift_option) } let(:mail_with_desc) { AdminMailer.notify_failed_gift(donation, payment, campaign_gift_option_with_desc) } @@ -40,5 +40,4 @@ expect(mail.body.encoded).to include("Description:") end end - end diff --git a/spec/mailers/dispute_mailer_spec.rb b/spec/mailers/dispute_mailer_spec.rb index 1897e91ad..2395f0880 100644 --- a/spec/mailers/dispute_mailer_spec.rb +++ b/spec/mailers/dispute_mailer_spec.rb @@ -1,17 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -RSpec.describe DisputeMailer, :type => :mailer do +RSpec.describe DisputeMailer, type: :mailer do around(:each) do |example| StripeMockHelper.mock do example.run end end - describe "created" do include_context :dispute_created_context do - let(:obj) { StripeDispute.create(object:json) } + let(:obj) { StripeDispute.create(object: json) } end let(:mail) { DisputeMailer.created(dispute) } @@ -24,7 +23,7 @@ describe "funds_withdrawn" do include_context :dispute_funds_withdrawn_context - let(:obj) { StripeDispute.create(object:json) } + let(:obj) { StripeDispute.create(object: json) } let(:mail) { DisputeMailer.funds_withdrawn(dispute) } it "renders the headers" do @@ -36,7 +35,7 @@ describe "funds_reinstated" do include_context :dispute_funds_reinstated_context - let(:obj) { StripeDispute.create(object:json) } + let(:obj) { StripeDispute.create(object: json) } let(:mail) { DisputeMailer.funds_reinstated(dispute) } it "renders the headers" do @@ -48,8 +47,8 @@ describe "won" do include_context :dispute_won_context - - let(:obj) { StripeDispute.create(object:json) } + + let(:obj) { StripeDispute.create(object: json) } let(:mail) { DisputeMailer.won(dispute) } it "renders the headers" do @@ -61,7 +60,7 @@ describe "lost" do include_context :dispute_lost_context - let(:obj) { StripeDispute.create(object:json) } + let(:obj) { StripeDispute.create(object: json) } let(:dispute) { obj.dispute } let(:mail) { DisputeMailer.lost(dispute) } @@ -78,19 +77,21 @@ example.run end end - let(:nonprofit) { force_create(:nonprofit, name: "spec_nonprofit_full")} + let(:nonprofit) { force_create(:nonprofit, name: "spec_nonprofit_full") } let(:json) do - event =StripeMockHelper.mock_webhook_event('charge.dispute.updated') - event['data']['object'] + event = StripeMockHelper.mock_webhook_event("charge.dispute.updated") + event["data"]["object"] end - let(:supporter) { force_create(:supporter, nonprofit: nonprofit)} - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} - - let(:obj) { StripeDispute.create(object:json) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } + + let(:obj) { StripeDispute.create(object: json) } let(:dispute) { obj.dispute } let(:mail) { DisputeMailer.updated(dispute) } @@ -100,5 +101,4 @@ expect(mail.from).to eq(["support@commitchange.com"]) end end - end diff --git a/spec/mailers/donation_mailer_spec.rb b/spec/mailers/donation_mailer_spec.rb index 443ae4fa7..81e74716d 100644 --- a/spec/mailers/donation_mailer_spec.rb +++ b/spec/mailers/donation_mailer_spec.rb @@ -1,16 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -RSpec.describe DonationMailer, :type => :mailer do +RSpec.describe DonationMailer, type: :mailer do describe "donor_recurring_donation_change_amount" do - let(:np) { force_create(:nonprofit, name: "nonprofit", email: 'blah')} - let(:s) { force_create(:supporter, email: 'supporter.email@mail.teha')} - let(:oldcard) { force_create(:card)} - let(:donation) {create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999)} - let(:default_message) { 'You have successfully changed your recurring donation amount. Please see the receipt and details below.'} + let(:np) { force_create(:nonprofit, name: "nonprofit", email: "blah") } + let(:s) { force_create(:supporter, email: "supporter.email@mail.teha") } + let(:oldcard) { force_create(:card) } + let(:donation) { create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999) } + let(:default_message) { "You have successfully changed your recurring donation amount. Please see the receipt and details below." } let(:rd) { - inner_rd = create(:recurring_donation, amount:999, active:true, supporter_id: s.id, donation_id: donation.id, nonprofit_id: np.id, start_date: Date.today, interval:1, time_unit:'month')} + create(:recurring_donation, amount: 999, active: true, supporter_id: s.id, donation_id: donation.id, nonprofit_id: np.id, start_date: Date.today, interval: 1, time_unit: "month") + } before(:each) { np @@ -19,14 +20,14 @@ donation default_message } - describe 'with custom' do - let(:custom_message) { 'custom_message'} - let!(:custom_donor_amount) { create(:miscellaneous_np_info, :change_amount_message => custom_message, :nonprofit => np)} + describe "with custom" do + let(:custom_message) { "custom_message" } + let!(:custom_donor_amount) { create(:miscellaneous_np_info, change_amount_message: custom_message, nonprofit: np) } let!(:mail) { DonationMailer.donor_recurring_donation_change_amount(rd.id, 1000) } it "renders the headers" do - expect(mail.subject).to eq( "Recurring donation amount changed for #{np.name}") - expect(mail.to).to eq(['supporter.email@mail.teha']) + expect(mail.subject).to eq("Recurring donation amount changed for #{np.name}") + expect(mail.to).to eq(["supporter.email@mail.teha"]) expect(mail.reply_to).to eq([np.email]) end @@ -36,14 +37,13 @@ end end - - describe 'without custom message' do - let!(:custom_donor_amount) { create(:miscellaneous_np_info, :nonprofit => np)} + describe "without custom message" do + let!(:custom_donor_amount) { create(:miscellaneous_np_info, nonprofit: np) } let!(:mail) { DonationMailer.donor_recurring_donation_change_amount(rd.id, 1000) } it "renders the headers" do - expect(mail.subject).to eq( "Recurring donation amount changed for #{np.name}") - expect(mail.to).to eq(['supporter.email@mail.teha']) + expect(mail.subject).to eq("Recurring donation amount changed for #{np.name}") + expect(mail.to).to eq(["supporter.email@mail.teha"]) expect(mail.reply_to).to eq([np.email]) end @@ -52,12 +52,11 @@ end end - describe 'without miscinfo' do - + describe "without miscinfo" do let!(:mail) { DonationMailer.donor_recurring_donation_change_amount(rd.id, 1000) } it "renders the headers" do - expect(mail.subject).to eq( "Recurring donation amount changed for #{np.name}") - expect(mail.to).to eq(['supporter.email@mail.teha']) + expect(mail.subject).to eq("Recurring donation amount changed for #{np.name}") + expect(mail.to).to eq(["supporter.email@mail.teha"]) expect(mail.reply_to).to eq([np.email]) end @@ -65,250 +64,249 @@ expect(mail.body.encoded).to match "#{default_message}" end end - - - end describe "donor_payment_notification" do - let(:thank_you_note_default) {'thank you Supporter'} - let(:thank_you_note_named) {'thank you Penelope'} - let(:campaign_custom_default) { 'Supporter'} - let(:campaign_custom_named) { 'Penelope'} - let(:np) { force_create(:nonprofit, name: "nonprofit", email: 'blah', thank_you_note: 'thank you {{FIRSTNAME}}')} - let(:s) { force_create(:supporter, email: 'supporter.email@mail.teha', name: '')} - let(:s_with_name) { force_create(:supporter, email: 'supporter.email@mail.teha', name: 'Penelope')} - let(:oldcard) { force_create(:card)} + let(:thank_you_note_default) { "thank you Supporter" } + let(:thank_you_note_named) { "thank you Penelope" } + let(:campaign_custom_default) { "Supporter" } + let(:campaign_custom_named) { "Penelope" } + let(:np) { force_create(:nonprofit, name: "nonprofit", email: "blah", thank_you_note: "thank you {{FIRSTNAME}}") } + let(:s) { force_create(:supporter, email: "supporter.email@mail.teha", name: "") } + let(:s_with_name) { force_create(:supporter, email: "supporter.email@mail.teha", name: "Penelope") } + let(:oldcard) { force_create(:card) } let(:charge) { force_create(:charge, payment_id: payment.id, supporter_id: s.id, amount: 999) } let(:payment) { force_create(:payment, donation_id: donation.id, supporter_id: s.id, gross_amount: 999) } - let(:donation) {force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999)} - + let(:donation) { force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999) } + let(:charge_with_campaign) { force_create(:charge, payment_id: payment_with_campaign.id, supporter_id: s.id, amount: 999) } let(:payment_with_campaign) { force_create(:payment, donation_id: donation_with_campaign.id, supporter_id: s.id, gross_amount: 999) } - let(:donation_with_campaign) {force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999, campaign_id: campaign.id)} - + let(:donation_with_campaign) { force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999, campaign_id: campaign.id) } + let(:charge_with_custom_campaign_message) { force_create(:charge, payment_id: payment_with_custom_campaign_message.id, supporter_id: s.id, amount: 999) } let(:payment_with_custom_campaign_message) { force_create(:payment, donation_id: donation_with_custom_campaign_message.id, supporter_id: s.id, gross_amount: 999) } - let(:donation_with_custom_campaign_message) {force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999, campaign_id: campaign_with_custom_message.id)} - + let(:donation_with_custom_campaign_message) { force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999, campaign_id: campaign_with_custom_message.id) } + let(:charge_with_invalid_custom_campaign_message) { force_create(:charge, payment_id: payment_with_invalid_custom_campaign_message.id, supporter_id: s.id, amount: 999) } let(:payment_with_invalid_custom_campaign_message) { force_create(:payment, donation_id: donation_with_invalid_custom_campaign_message.id, supporter_id: s.id, gross_amount: 999) } - let(:donation_with_invalid_custom_campaign_message) {force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999, campaign_id: campaign_with_invalid_custom_message.id)} - + let(:donation_with_invalid_custom_campaign_message) { force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999, campaign_id: campaign_with_invalid_custom_message.id) } + let(:charge_named) { force_create(:charge, payment_id: payment_named.id, supporter_id: s_with_name.id, amount: 999) } let(:payment_named) { force_create(:payment, donation_id: donation_named.id, supporter_id: s_with_name.id, gross_amount: 999) } - let(:donation_named) { force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount:999) } + let(:donation_named) { force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount: 999) } let(:charge_with_campaign_named) { force_create(:charge, payment_id: payment_with_campaign_named.id, supporter_id: s_with_name.id, amount: 999) } let(:payment_with_campaign_named) { force_create(:payment, donation_id: donation_with_campaign_named.id, supporter_id: s_with_name.id, gross_amount: 999) } - let(:donation_with_campaign_named) {force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount:999, campaign_id: campaign.id)} + let(:donation_with_campaign_named) { force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount: 999, campaign_id: campaign.id) } let(:charge_with_custom_campaign_message_named) { force_create(:charge, payment_id: payment_with_custom_campaign_message_named.id, supporter_id: s_with_name.id, amount: 999) } let(:payment_with_custom_campaign_message_named) { force_create(:payment, donation_id: donation_with_custom_campaign_message_named.id, supporter_id: s_with_name.id, gross_amount: 999) } - let(:donation_with_custom_campaign_message_named) {force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount:999, campaign_id: campaign_with_custom_message.id)} + let(:donation_with_custom_campaign_message_named) { force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount: 999, campaign_id: campaign_with_custom_message.id) } let(:charge_with_invalid_custom_campaign_message_named) { force_create(:charge, payment_id: payment_with_invalid_custom_campaign_message_named.id, supporter_id: s_with_name.id, amount: 999) } let(:payment_with_invalid_custom_campaign_message_named) { force_create(:payment, donation_id: donation_with_invalid_custom_campaign_message_named.id, supporter_id: s_with_name.id, gross_amount: 999) } - let(:donation_with_invalid_custom_campaign_message_named) {force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount:999, campaign_id: campaign_with_invalid_custom_message.id)} - + let(:donation_with_invalid_custom_campaign_message_named) { force_create(:donation, nonprofit_id: np.id, supporter_id: s_with_name.id, card_id: oldcard.id, amount: 999, campaign_id: campaign_with_invalid_custom_message.id) } - let(:campaign) {force_create(:campaign, nonprofit_id: np.id)} - let(:campaign_with_custom_message) { force_create(:campaign, nonprofit_id: np.id, receipt_message: "{{FIRSTNAME}}")} - let(:campaign_with_invalid_custom_message) { force_create(:campaign, nonprofit_id: np.id, receipt_message: "")} + let(:campaign) { force_create(:campaign, nonprofit_id: np.id) } + let(:campaign_with_custom_message) { force_create(:campaign, nonprofit_id: np.id, receipt_message: "{{FIRSTNAME}}") } + let(:campaign_with_invalid_custom_message) { force_create(:campaign, nonprofit_id: np.id, receipt_message: "") } - describe 'no name supporter' do - describe 'no campaign' do - let(:mail) { DonationMailer.donor_payment_notification(donation.id,payment.id)} - it 'contains default thank you note' do + describe "no name supporter" do + describe "no campaign" do + let(:mail) { DonationMailer.donor_payment_notification(donation.id, payment.id) } + it "contains default thank you note" do expect(mail.body.encoded).to include thank_you_note_default end end - describe 'campaign' do - let(:mail) { DonationMailer.donor_payment_notification(donation_with_campaign.id, payment_with_campaign.id)} - it 'contains default thank you note' do + describe "campaign" do + let(:mail) { DonationMailer.donor_payment_notification(donation_with_campaign.id, payment_with_campaign.id) } + it "contains default thank you note" do expect(mail.body.encoded).to include thank_you_note_default end end - describe 'campaign_with_custom' do - let(:mail) { DonationMailer.donor_payment_notification(donation_with_custom_campaign_message.id, payment_with_custom_campaign_message.id)} - it 'contains default campaign' do + describe "campaign_with_custom" do + let(:mail) { DonationMailer.donor_payment_notification(donation_with_custom_campaign_message.id, payment_with_custom_campaign_message.id) } + it "contains default campaign" do expect(mail.body.encoded).to include campaign_custom_default end end - describe 'campaign with invalid custom' do - let(:mail) { DonationMailer.donor_payment_notification(donation_with_invalid_custom_campaign_message.id, payment_with_invalid_custom_campaign_message.id)} - it 'contains default thank you note' do + describe "campaign with invalid custom" do + let(:mail) { DonationMailer.donor_payment_notification(donation_with_invalid_custom_campaign_message.id, payment_with_invalid_custom_campaign_message.id) } + it "contains default thank you note" do expect(mail.body.encoded).to include thank_you_note_default end end end - describe 'named supporter' do - describe 'no campaign' do - let(:mail) { DonationMailer.donor_payment_notification(donation_named.id, payment_named.id)} - it 'contains named thank you note' do + describe "named supporter" do + describe "no campaign" do + let(:mail) { DonationMailer.donor_payment_notification(donation_named.id, payment_named.id) } + it "contains named thank you note" do expect(mail.body.encoded).to include thank_you_note_named end end - describe 'campaign' do - let(:mail) { DonationMailer.donor_payment_notification(donation_with_campaign_named.id, payment_with_campaign_named.id)} - it 'contains named thank you note' do + describe "campaign" do + let(:mail) { DonationMailer.donor_payment_notification(donation_with_campaign_named.id, payment_with_campaign_named.id) } + it "contains named thank you note" do expect(mail.body.encoded).to include thank_you_note_named end end - describe 'campaign_with_custom' do - let(:mail) { DonationMailer.donor_payment_notification(donation_with_custom_campaign_message_named.id, payment_with_custom_campaign_message_named.id)} - it 'contains named campaign' do + describe "campaign_with_custom" do + let(:mail) { DonationMailer.donor_payment_notification(donation_with_custom_campaign_message_named.id, payment_with_custom_campaign_message_named.id) } + it "contains named campaign" do expect(mail.body.encoded).to include campaign_custom_named end end - describe 'campaign with invalid custom' do - let(:mail) { DonationMailer.donor_payment_notification(donation_with_invalid_custom_campaign_message_named.id, payment_with_invalid_custom_campaign_message_named.id)} - it 'contains named thank you note' do + describe "campaign with invalid custom" do + let(:mail) { DonationMailer.donor_payment_notification(donation_with_invalid_custom_campaign_message_named.id, payment_with_invalid_custom_campaign_message_named.id) } + it "contains named thank you note" do expect(mail.body.encoded).to include thank_you_note_named end end end - describe 'specific recurring donation payment' do - + describe "specific recurring donation payment" do let(:recurring_donation) do - rd = force_create(:recurring_donation, donation_id: donation.id, supporter_id: s.id, nonprofit_id: np.id, amount: 999) - + force_create(:recurring_donation, donation_id: donation.id, supporter_id: s.id, nonprofit_id: np.id, amount: 999) + payment_to_send_receipt_for other_payment end - let(:donation) {force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount:999)} - - let(:payment_to_send_receipt_for) { force_create(:payment, supporter_id: s.id, amount: 999, donation_id: donation.id, date: Time.at(2020, 5, 1))} - let(:other) { force_create(:payment, supporter_id: s.id, amount: 999, donation_id: donation.id, date: Time.at(2020, 5, 1))} - - - - + let(:donation) { force_create(:donation, nonprofit_id: np.id, supporter_id: s.id, card_id: oldcard.id, amount: 999) } + let(:payment_to_send_receipt_for) { force_create(:payment, supporter_id: s.id, amount: 999, donation_id: donation.id, date: Time.at(2020, 5, 1)) } + let(:other) { force_create(:payment, supporter_id: s.id, amount: 999, donation_id: donation.id, date: Time.at(2020, 5, 1)) } end end describe "#nonprofit_payment_notification" do - - context 'when supporter name is set' do + context "when supporter name is set" do before(:each) { - expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(['anything@example.com']) + expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(["anything@example.com"]) } - - let(:supporter) { create(:supporter_base)} - let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit)} - let(:payment) { create(:payment_base, donation: donation)} - - let!(:mail) { DonationMailer.nonprofit_payment_notification( - donation.id, - payment.id - ) } - - it 'uses the supporter name in subject' do + + let(:supporter) { create(:supporter_base) } + let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit) } + let(:payment) { create(:payment_base, donation: donation) } + + let!(:mail) { + DonationMailer.nonprofit_payment_notification( + donation.id, + payment.id + ) + } + + it "uses the supporter name in subject" do expect(mail.subject).to include supporter.name end end - - context 'when supporter name is nil' do + context "when supporter name is nil" do before(:each) { - expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(['anything@example.com']) + expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(["anything@example.com"]) + } + + let(:supporter) { create(:supporter_base, email: "supporter@example.com", name: nil) } + let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit) } + let(:payment) { create(:payment_base, donation: donation) } + + let!(:mail) { + DonationMailer.nonprofit_payment_notification( + donation.id, + payment.id + ) } - - let(:supporter) { create(:supporter_base, email: "supporter@example.com", name: nil)} - let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit)} - let(:payment) { create(:payment_base, donation: donation)} - - let!(:mail) { DonationMailer.nonprofit_payment_notification( - donation.id, - payment.id - ) } - - it 'uses the supporter email instead of name in subject' do + + it "uses the supporter email instead of name in subject" do expect(mail.subject).to include supporter.email end end - context 'when supporter name is blank', pending: true do + context "when supporter name is blank", pending: true do before(:each) { - expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(['anything@example.com']) + expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(["anything@example.com"]) + } + + let(:supporter) { create(:supporter_base, email: "supporter@example.com", name: "") } + let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit) } + let(:payment) { create(:payment_base, donation: donation) } + + let!(:mail) { + DonationMailer.nonprofit_payment_notification( + donation.id, + payment.id + ) } - - let(:supporter) { create(:supporter_base, email: "supporter@example.com", name: "")} - let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit)} - let(:payment) { create(:payment_base, donation: donation)} - - let!(:mail) { DonationMailer.nonprofit_payment_notification( - donation.id, - payment.id - ) } - - - it 'uses the supporter email instead of name in subject' do + + it "uses the supporter email instead of name in subject" do expect(mail.subject).to include supporter.email end end - context 'when dedication is not set' do + context "when dedication is not set" do before(:each) { - expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(['anything@example.com']) + expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(["anything@example.com"]) } - let(:supporter) { create(:supporter_base)} - let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit)} - let(:payment) { create(:payment_base, donation: donation)} + let(:supporter) { create(:supporter_base) } + let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit) } + let(:payment) { create(:payment_base, donation: donation) } - let!(:mail) { DonationMailer.nonprofit_payment_notification( - donation.id, - payment.id - ) } + let!(:mail) { + DonationMailer.nonprofit_payment_notification( + donation.id, + payment.id + ) + } - it 'does not include the dedication section' do + it "does not include the dedication section" do expect(mail.body.encoded).to_not include "Acknowledgement Phone" end end - context 'when dedication is blank' do + context "when dedication is blank" do before(:each) { - expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(['anything@example.com']) + expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(["anything@example.com"]) } - let(:supporter) { create(:supporter_base)} - let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit, dedication: '')} - let(:payment) { create(:payment_base, donation: donation)} + let(:supporter) { create(:supporter_base) } + let(:donation) { create(:donation_base, supporter: supporter, nonprofit: supporter.nonprofit, dedication: "") } + let(:payment) { create(:payment_base, donation: donation) } - let!(:mail) { DonationMailer.nonprofit_payment_notification( - donation.id, - payment.id - ) } + let!(:mail) { + DonationMailer.nonprofit_payment_notification( + donation.id, + payment.id + ) + } - it 'does not include the dedication section' do + it "does not include the dedication section" do expect(mail.body.encoded).to_not include "Acknowledgement Phone" end end - context 'when dedication is set' do + context "when dedication is set" do before(:each) { - expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(['anything@example.com']) + expect(QueryUsers).to receive(:nonprofit_user_emails).and_return(["anything@example.com"]) } - let(:supporter) { create(:supporter_base)} - let(:donation) { create(:donation_with_dedication, supporter: supporter, nonprofit: supporter.nonprofit)} - let(:payment) { create(:payment_base, donation: donation)} + let(:supporter) { create(:supporter_base) } + let(:donation) { create(:donation_with_dedication, supporter: supporter, nonprofit: supporter.nonprofit) } + let(:payment) { create(:payment_base, donation: donation) } - let!(:mail) { DonationMailer.nonprofit_payment_notification( - donation.id, - payment.id - ) } + let!(:mail) { + DonationMailer.nonprofit_payment_notification( + donation.id, + payment.id + ) + } - it 'does not include the dedication section' do + it "does not include the dedication section" do expect(mail.body.encoded).to include "Acknowledgement Phone" expect(mail.body.encoded).to include "234-343-3234" end diff --git a/spec/mailers/nonprofit_mailer_spec.rb b/spec/mailers/nonprofit_mailer_spec.rb index 2a2205887..7625da3c8 100644 --- a/spec/mailers/nonprofit_mailer_spec.rb +++ b/spec/mailers/nonprofit_mailer_spec.rb @@ -1,14 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -RSpec.describe NonprofitMailer, :type => :mailer do +RSpec.describe NonprofitMailer, type: :mailer do describe "first_charge_email" do - let(:np) {create(:nonprofit, stripe_account_id: 'acct_id')} - let(:user) {create(:user)} - let(:role) {create(:role, host: np, user: user, name: :nonprofit_admin)} - let(:bank_account) {create(:bank_account, nonprofit: np, pending_verification:false)} - let(:stripe_account) {create(:stripe_account, payouts_enabled:true, stripe_account_id: 'acct_id')} - + let(:np) { create(:nonprofit, stripe_account_id: "acct_id") } + let(:user) { create(:user) } + let(:role) { create(:role, host: np, user: user, name: :nonprofit_admin) } + let(:bank_account) { create(:bank_account, nonprofit: np, pending_verification: false) } + let(:stripe_account) { create(:stripe_account, payouts_enabled: true, stripe_account_id: "acct_id") } let(:mail) do role @@ -27,40 +26,39 @@ NonprofitMailer.first_charge_email(np.id) end - describe 'no bank account, no stripe account' do + describe "no bank account, no stripe account" do subject { mail } - it 'recommends to setup bank account' do - expect(mail.body.encoded).to include 'you need to connect your' + it "recommends to setup bank account" do + expect(mail.body.encoded).to include "you need to connect your" end - - it 'recommends to verify stripe' do - expect(mail.body.encoded).to include 'Stripe is requested additional verification' + + it "recommends to verify stripe" do + expect(mail.body.encoded).to include "Stripe is requested additional verification" end - it 'sets the X-SES-CONFIGURATION-SET' do - expect(mail["X-SES-CONFIGURATION-SET"].value).to eq 'Admin' + it "sets the X-SES-CONFIGURATION-SET" do + expect(mail["X-SES-CONFIGURATION-SET"].value).to eq "Admin" end end - describe 'no stripe account' do - it 'does not recommends to setup bank account' do - expect(mail_with_bank_account.body.encoded).to_not include 'you need to connect your' + describe "no stripe account" do + it "does not recommends to setup bank account" do + expect(mail_with_bank_account.body.encoded).to_not include "you need to connect your" end - - it 'recommends to verify stripe' do - expect(mail_with_bank_account.body.encoded).to include 'Stripe is requested additional verification' + + it "recommends to verify stripe" do + expect(mail_with_bank_account.body.encoded).to include "Stripe is requested additional verification" end end - describe 'no bank account' do - it 'recommends to setup bank account' do - expect(mail_with_stripe_account.body.encoded).to include 'you need to connect your' + describe "no bank account" do + it "recommends to setup bank account" do + expect(mail_with_stripe_account.body.encoded).to include "you need to connect your" end - - it 'does not recommends to verify stripe' do - expect(mail_with_stripe_account.body.encoded).to_not include 'Stripe is requested additional verification' + + it "does not recommends to verify stripe" do + expect(mail_with_stripe_account.body.encoded).to_not include "Stripe is requested additional verification" end end - end -end \ No newline at end of file +end diff --git a/spec/mailers/previews/tax_mailer_preview.rb b/spec/mailers/previews/tax_mailer_preview.rb index b62dffd35..087ff577e 100644 --- a/spec/mailers/previews/tax_mailer_preview.rb +++ b/spec/mailers/previews/tax_mailer_preview.rb @@ -4,47 +4,40 @@ class TaxMailerPreview < ActionMailer::Preview include FactoryBot::Syntax::Methods # Preview this email at http://localhost:5000/rails/mailers/tax_mailer/annual_receipt def annual_receipt - payments = build_list(:donation_payment_generator, Random.rand(5) + 1, - supporter: supporter, - nonprofit: supporter.nonprofit - ) + payments = build_list(:donation_payment_generator, Random.rand(1..5), + supporter: supporter, + nonprofit: supporter.nonprofit) TaxMailer.annual_receipt(year: tax_year, supporter: supporter, nonprofit_text: nonprofit_text, donation_payments: payments) end # Preview this email at http://localhost:5000/rails/mailers/tax_mailer/annual_receipt_with_refunds def annual_receipt_with_refunds - payments = build_list(:donation_payment_generator, Random.rand(5) + 1, - supporter: supporter, - nonprofit: supporter.nonprofit - ) + payments = build_list(:donation_payment_generator, Random.rand(1..5), + supporter: supporter, + nonprofit: supporter.nonprofit) - refund_payments = build_list(:refund_payment_generator, Random.rand(5) + 1, + refund_payments = build_list(:refund_payment_generator, Random.rand(1..5), supporter: supporter, - nonprofit: supporter.nonprofit - ) + nonprofit: supporter.nonprofit) TaxMailer.annual_receipt(year: tax_year, supporter: supporter, nonprofit_text: nonprofit_text, donation_payments: payments, refund_payments: refund_payments) end - # Preview this email at http://localhost:5000/rails/mailers/tax_mailer/annual_receipt_with_disputes - def annual_receipt_with_disputes - payments = build_list(:donation_payment_generator, Random.rand(5) + 1, - supporter: supporter, - nonprofit: supporter.nonprofit - ) + # Preview this email at http://localhost:5000/rails/mailers/tax_mailer/annual_receipt_with_disputes + def annual_receipt_with_disputes + payments = build_list(:donation_payment_generator, Random.rand(1..5), + supporter: supporter, + nonprofit: supporter.nonprofit) - dispute_payments = build_list(:dispute_payment_generator, Random.rand(5) + 1, + dispute_payments = build_list(:dispute_payment_generator, Random.rand(1..5), supporter: supporter, - nonprofit: supporter.nonprofit - ) + nonprofit: supporter.nonprofit) - dispute_reversal_payments = build_list(:dispute_reversal_payment_generator, Random.rand(5) + 0, + dispute_reversal_payments = build_list(:dispute_reversal_payment_generator, Random.rand(0..4), supporter: supporter, - nonprofit: supporter.nonprofit - ) + nonprofit: supporter.nonprofit) TaxMailer.annual_receipt(year: tax_year, supporter: supporter, nonprofit_text: nonprofit_text, donation_payments: payments, dispute_payments: dispute_payments, dispute_reversal_payments: dispute_reversal_payments) end - private def nonprofit diff --git a/spec/mailers/stripe_account_mailer_spec.rb b/spec/mailers/stripe_account_mailer_spec.rb index 7fdbe3b4b..85b992cf5 100644 --- a/spec/mailers/stripe_account_mailer_spec.rb +++ b/spec/mailers/stripe_account_mailer_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" -RSpec.describe StripeAccountMailer, :type => :mailer do +RSpec.describe StripeAccountMailer, type: :mailer do describe "no_longer_verified" do - let(:np) {create(:nonprofit, timezone: "America/Chicago")} - let(:user) {create(:user)} - let(:role) {create(:role, host: np, user: user, name: :nonprofit_admin)} - let(:deadline) { Time.new(2020,2,3,22,32,12)} - let(:deadline_string) { "February 3, 2020 at 4:32:12 PM"} - let(:generic_deadline_substring) { "advised to complete this"} + let(:np) { create(:nonprofit, timezone: "America/Chicago") } + let(:user) { create(:user) } + let(:role) { create(:role, host: np, user: user, name: :nonprofit_admin) } + let(:deadline) { Time.new(2020, 2, 3, 22, 32, 12) } + let(:deadline_string) { "February 3, 2020 at 4:32:12 PM" } + let(:generic_deadline_substring) { "advised to complete this" } let(:mail) do role @@ -28,14 +28,14 @@ expect(mail_no_deadline.body.encoded).to include(generic_deadline_substring) end end - + describe "not_completed" do - let(:np) {create(:nonprofit, timezone: "America/Chicago")} - let(:user) {create(:user)} - let(:role) {create(:role, host: np, user: user, name: :nonprofit_admin)} - let(:deadline) { Time.new(2020,2,3,22,32,12)} - let(:deadline_string) { "February 3, 2020 at 4:32:12 PM"} - let(:generic_deadline_substring) { "advised to complete this"} + let(:np) { create(:nonprofit, timezone: "America/Chicago") } + let(:user) { create(:user) } + let(:role) { create(:role, host: np, user: user, name: :nonprofit_admin) } + let(:deadline) { Time.new(2020, 2, 3, 22, 32, 12) } + let(:deadline_string) { "February 3, 2020 at 4:32:12 PM" } + let(:generic_deadline_substring) { "advised to complete this" } let(:mail) do role @@ -57,12 +57,12 @@ end describe "more_info_needed" do - let(:np) {create(:nonprofit, timezone: "America/Chicago")} - let(:user) {create(:user)} - let(:role) {create(:role, host: np, user: user, name: :nonprofit_admin)} - let(:deadline) { Time.new(2020,2,3,22,32,12)} - let(:deadline_string) { "February 3, 2020 at 4:32:12 PM"} - let(:generic_deadline_substring) { "advised to complete this"} + let(:np) { create(:nonprofit, timezone: "America/Chicago") } + let(:user) { create(:user) } + let(:role) { create(:role, host: np, user: user, name: :nonprofit_admin) } + let(:deadline) { Time.new(2020, 2, 3, 22, 32, 12) } + let(:deadline_string) { "February 3, 2020 at 4:32:12 PM" } + let(:generic_deadline_substring) { "advised to complete this" } let(:mail) do role @@ -82,4 +82,4 @@ expect(mail_no_deadline.body.encoded).to include(generic_deadline_substring) end end -end \ No newline at end of file +end diff --git a/spec/migration/migration_sanity_spec.rb b/spec/migration/migration_sanity_spec.rb index 8aac25b4e..a411fb2c9 100644 --- a/spec/migration/migration_sanity_spec.rb +++ b/spec/migration/migration_sanity_spec.rb @@ -1,24 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -describe 'Migration sanity' do - - it 'Migrations have a sane timestamp' do - Dir.open(File.join(Rails.root, 'db', 'migrate')) do |dir| - #should be a hash but we don't have in Ruby 2.3 +describe "Migration sanity" do + it "Migrations have a sane timestamp" do + Dir.open(Rails.root.join("db/migrate").to_s) do |dir| + # should be a hash but we don't have in Ruby 2.3 migration_names = [] dir.entries.each do |file| - if file != '.' && file != '..' - ret = file.split('_', 2) + if file != "." && file != ".." + ret = file.split("_", 2) expect(ret[0].length).to eq 14 - expect{ Integer(ret[0])}.to_not raise_error + expect { Integer(ret[0]) }.to_not raise_error expect(migration_names).to_not include ret[1] migration_names.push(ret[1]) end end - end end -end \ No newline at end of file +end diff --git a/spec/models/billing_plan_spec.rb b/spec/models/billing_plan_spec.rb index 8c12b0347..31f961166 100644 --- a/spec/models/billing_plan_spec.rb +++ b/spec/models/billing_plan_spec.rb @@ -1,38 +1,36 @@ - -require 'rails_helper' +require "rails_helper" RSpec.describe BillingPlan, type: :model do - - context 'validation' do - it {is_expected.to validate_presence_of(:amount)} - it {is_expected.to validate_presence_of(:percentage_fee)} + context "validation" do + it { is_expected.to validate_presence_of(:amount) } + it { is_expected.to validate_presence_of(:percentage_fee) } - it {is_expected.to validate_numericality_of(:percentage_fee).is_less_than(1).is_greater_than_or_equal_to(0)} + it { is_expected.to validate_numericality_of(:percentage_fee).is_less_than(1).is_greater_than_or_equal_to(0) } - it{ is_expected.to validate_numericality_of(:flat_fee).is_greater_than_or_equal_to(0).only_integer} + it { is_expected.to validate_numericality_of(:flat_fee).is_greater_than_or_equal_to(0).only_integer } - it {is_expected.to have_many(:billing_subscriptions)} + it { is_expected.to have_many(:billing_subscriptions) } end - - describe '::PathCaching' do - describe '.clear_cache' do - it 'clears the cache when an id is passed' do + + describe "::PathCaching" do + describe ".clear_cache" do + it "clears the cache when an id is passed" do expect(Rails.cache).to receive(:delete).with("billing_plan_nonprofit_id_1") described_class.clear_cache(1) end - it 'clears the cache when an nonprofit is passed' do + it "clears the cache when an nonprofit is passed" do np = create(:nonprofit) expect(Rails.cache).to receive(:delete).with("billing_plan_nonprofit_id_#{np.id}") described_class.clear_cache(np) end end - describe '.create_cache_key' do - it 'clears the proper key when id is an integer' do + describe ".create_cache_key" do + it "clears the proper key when id is an integer" do expect(described_class.create_cache_key(1)).to eq "billing_plan_nonprofit_id_1" end - it 'clears the proper key when id is a nonprofit' do + it "clears the proper key when id is a nonprofit" do np = create(:nonprofit) expect(described_class.create_cache_key(np)).to eq "billing_plan_nonprofit_id_#{np.id}" end diff --git a/spec/models/billing_subscription_spec.rb b/spec/models/billing_subscription_spec.rb index eb69113f7..54b1be364 100644 --- a/spec/models/billing_subscription_spec.rb +++ b/spec/models/billing_subscription_spec.rb @@ -1,20 +1,17 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe BillingSubscription, type: :model do - - describe '::PathCaching' do - - describe 'after save' do - it 'calls Nonprofit#clear_cache after create' do + describe "::PathCaching" do + describe "after save" do + it "calls Nonprofit#clear_cache after create" do billing_subscription = build(:billing_subscription) np = billing_subscription.nonprofit expect(np).to receive(:clear_cache).thrice # once for nonprofit, once for billing subscription, once for billing plan billing_subscription.save! end - - it 'calls Nonprofit#clear_cache after update' do + it "calls Nonprofit#clear_cache after update" do billing_subscription = create(:billing_subscription) np = billing_subscription.nonprofit expect(np).to receive(:clear_cache).once @@ -22,25 +19,25 @@ billing_subscription.save! end end - describe '.clear_cache' do - it 'clears the cache when an id is passed' do + describe ".clear_cache" do + it "clears the cache when an id is passed" do expect(Rails.cache).to receive(:delete).with("billing_subscription_nonprofit_id_1") described_class.clear_cache(1) end - it 'clears the cache when an nonprofit is passed' do + it "clears the cache when an nonprofit is passed" do np = create(:nonprofit) expect(Rails.cache).to receive(:delete).with("billing_subscription_nonprofit_id_#{np.id}") described_class.clear_cache(np) end end - describe '.create_cache_key' do - it 'clears the proper key when id is an integer' do + describe ".create_cache_key" do + it "clears the proper key when id is an integer" do expect(described_class.create_cache_key(1)).to eq "billing_subscription_nonprofit_id_1" end - it 'clears the proper key when id is a nonprofit' do + it "clears the proper key when id is a nonprofit" do np = create(:nonprofit) expect(described_class.create_cache_key(np)).to eq "billing_subscription_nonprofit_id_#{np.id}" end diff --git a/spec/models/campaign_gift_option_spec.rb b/spec/models/campaign_gift_option_spec.rb index 469f8d6ee..9fa9d1c34 100644 --- a/spec/models/campaign_gift_option_spec.rb +++ b/spec/models/campaign_gift_option_spec.rb @@ -1,32 +1,32 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe CampaignGiftOption, type: :model do - it {is_expected.to belong_to(:campaign).required(true)} - it {is_expected.to have_many(:campaign_gifts)} - it {is_expected.to have_many(:donations).through(:campaign_gifts)} - it {is_expected.to have_one(:nonprofit).through(:campaign)} + it { is_expected.to belong_to(:campaign).required(true) } + it { is_expected.to have_many(:campaign_gifts) } + it { is_expected.to have_many(:donations).through(:campaign_gifts) } + it { is_expected.to have_one(:nonprofit).through(:campaign) } - it {is_expected.to validate_presence_of(:name)} + it { is_expected.to validate_presence_of(:name) } describe "#gifts_available?" do - it 'when quantity nil' do + it "when quantity nil" do expect(build(:campaign_gift_option_base, quantity: nil)).to be_gifts_available end - it 'when quantity zero' do + it "when quantity zero" do expect(build(:campaign_gift_option_base, quantity: 0)).to be_gifts_available end - it 'when saved associated campaign gifts is less than quantity' do + it "when saved associated campaign gifts is less than quantity" do expect(build(:campaign_gift_option_base, quantity: 1)).to be_gifts_available end - it 'but not when saved campaign gifts is equal to quantity' do + it "but not when saved campaign gifts is equal to quantity" do expect(build(:campaign_gift_option_base, :with_one_campaign_gift, quantity: 1)).to be_gifts_available end - it 'but not when saved campaign gifts is more than quantity' do + it "but not when saved campaign gifts is more than quantity" do expect(build(:campaign_gift_option_base, :with_two_campaign_gifts, quantity: 1)).to be_gifts_available end end diff --git a/spec/models/campaign_spec.rb b/spec/models/campaign_spec.rb index 252bbb12d..83e7342ed 100644 --- a/spec/models/campaign_spec.rb +++ b/spec/models/campaign_spec.rb @@ -1,157 +1,147 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'carrierwave/test/matchers' +require "rails_helper" +require "carrierwave/test/matchers" def get_attributes_which_should_be_updated_keys - %w( + %w[ tagline body video_url receipt_message youtube_video_id summary vimeo_video_id - ) + ] end def get_attributes_which_should_not_be_updated_keys - %w( + %w[ slug goal_amount nonprofit_id profile_id show_total_raised show_total_count hide_activity_feed deleted hide_title hide_thermometer hide_goal hide_custom_amounts show_recurring_amount end_datetime external_identifier goal_is_in_supporters starting_point reason_for_supporting - ) + ] end def get_uploader_attribute_keys - %w( + %w[ main_image background_image banner_image - ) + ] end RSpec.describe Campaign, type: :model do include CarrierWave::Test::Matchers - it {is_expected.to belong_to :widget_description} + it { is_expected.to belong_to :widget_description } - describe 'goal_amount' do + describe "goal_amount" do before(:each) do @nonprofit = create(:nonprofit) - end - it 'when goal_is_in_supporters = true validate starting point and goal_amount' do - - campaign = Campaign.new(:starting_point => 'ethwohgniu', goal_is_in_supporters: true) + it "when goal_is_in_supporters = true validate starting point and goal_amount" do + campaign = Campaign.new(starting_point: "ethwohgniu", goal_is_in_supporters: true) campaign.valid? - expect(campaign.errors[:starting_point].any? {|i| i.include?("not a number")}).to be_truthy + expect(campaign.errors[:starting_point].any? { |i| i.include?("not a number") }).to be_truthy ["can't be blank", "not a number", "greater than or equal to 1"].each do |expected| - expect(campaign.errors[:goal_amount].any? {|i| i.include?(expected)}).to be_truthy + expect(campaign.errors[:goal_amount].any? { |i| i.include?(expected) }).to be_truthy end - campaign = Campaign.new(:starting_point => '1.3', goal_is_in_supporters: true, goal_amount: 4.5) + campaign = Campaign.new(starting_point: "1.3", goal_is_in_supporters: true, goal_amount: 4.5) campaign.valid? - expect(campaign.errors[:starting_point].any? {|i| i.include?("be an integer")}).to be_truthy + expect(campaign.errors[:starting_point].any? { |i| i.include?("be an integer") }).to be_truthy - expect(campaign.errors[:goal_amount].any? {|i| i.include?("be an integer")}).to be_truthy + expect(campaign.errors[:goal_amount].any? { |i| i.include?("be an integer") }).to be_truthy end - it 'when goal_is_in_supporters = false validate starting point and goal_amount' do - - campaign = Campaign.new(:starting_point => 'ethwohgniu', goal_is_in_supporters: false) + it "when goal_is_in_supporters = false validate starting point and goal_amount" do + campaign = Campaign.new(starting_point: "ethwohgniu", goal_is_in_supporters: false) campaign.valid? - expect(campaign.errors[:starting_point].any? {|i| i.include?("not a number")}).to be_truthy + expect(campaign.errors[:starting_point].any? { |i| i.include?("not a number") }).to be_truthy ["can't be blank", "not a number", "greater than or equal to 99"].each do |expected| - expect(campaign.errors[:goal_amount].any? {|i| i.include?(expected)}).to be_truthy + expect(campaign.errors[:goal_amount].any? { |i| i.include?(expected) }).to be_truthy end - campaign = Campaign.new(:starting_point => '1.3', goal_is_in_supporters: true, goal_amount: 4.5) + campaign = Campaign.new(starting_point: "1.3", goal_is_in_supporters: true, goal_amount: 4.5) campaign.valid? - expect(campaign.errors[:starting_point].any? {|i| i.include?("be an integer")}).to be_truthy + expect(campaign.errors[:starting_point].any? { |i| i.include?("be an integer") }).to be_truthy - expect(campaign.errors[:goal_amount].any? {|i| i.include?("be an integer")}).to be_truthy + expect(campaign.errors[:goal_amount].any? { |i| i.include?("be an integer") }).to be_truthy - campaign = Campaign.new(:starting_point => '-5', goal_is_in_supporters: true, goal_amount: 4.5) + campaign = Campaign.new(starting_point: "-5", goal_is_in_supporters: true, goal_amount: 4.5) campaign.valid? - expect(campaign.errors[:starting_point].any? {|i| i.include?("greater than or equal to 0")}).to be_truthy + expect(campaign.errors[:starting_point].any? { |i| i.include?("greater than or equal to 0") }).to be_truthy end - - end - describe 'sends correct email based on type of campaign' do - let(:nonprofit) { force_create(:nonprofit)} - let(:parent_campaign) { force_create(:campaign, name: 'Parent campaign', nonprofit: nonprofit) } + describe "sends correct email based on type of campaign" do + let(:nonprofit) { force_create(:nonprofit) } + let(:parent_campaign) { force_create(:campaign, name: "Parent campaign", nonprofit: nonprofit) } let(:child_campaign) do force_create(:campaign, - name: 'Child campaign', - parent_campaign_id: parent_campaign.id, - slug: "twehotiheiotheiofnieoth", - goal_amount_dollars: "1000", nonprofit: nonprofit ) + name: "Child campaign", + parent_campaign_id: parent_campaign.id, + slug: "twehotiheiotheiofnieoth", + goal_amount_dollars: "1000", nonprofit: nonprofit) end let(:html_body) do - ActionMailer::Base.deliveries.last.parts.select{|i| i.content_type.starts_with? 'text/html'}.first.body + ActionMailer::Base.deliveries.last.parts.select { |i| i.content_type.starts_with? "text/html" }.first.body end - it 'parent campaign sends out general campaign email' do + it "parent campaign sends out general campaign email" do expect { parent_campaign }.to change { ActionMailer::Base.deliveries.count }.by(1) expect(html_body.include?("Create one-time or recurring")).to be_truthy end - it 'child campaign sends out federated campaign email' do - expect { child_campaign}.to change { ActionMailer::Base.deliveries.count }.by(2) + it "child campaign sends out federated campaign email" do + expect { child_campaign }.to change { ActionMailer::Base.deliveries.count }.by(2) expect(html_body.include?("including a testimonial")).to be_truthy end end - - describe 'pausing' do - describe 'when no misc_campaign_info' do + describe "pausing" do + describe "when no misc_campaign_info" do subject { force_create(:campaign) } - it { is_expected.to_not be_paused} + it { is_expected.to_not be_paused } end - describe 'when misc_campaign_info exists but not paused' do + describe "when misc_campaign_info exists but not paused" do subject do campaign = force_create(:campaign) campaign.create_misc_campaign_info campaign end - it { is_expected.to_not be_paused} + it { is_expected.to_not be_paused } end - - describe 'when misc_campaign_info exists and is paused' do + describe "when misc_campaign_info exists and is paused" do subject do campaign = force_create(:campaign) campaign.create_misc_campaign_info(paused: true) campaign end - it { is_expected.to be_paused} + it { is_expected.to be_paused } end end + describe "#update_from_parent!" do + let(:empty_campaign) { create(:empty_campaign) } + let(:nonprofit) { empty_campaign.nonprofit } + let(:campaign_with_things_set_1) { create(:campaign_with_things_set_1, nonprofit: nonprofit) } - describe '#update_from_parent!' do - let(:empty_campaign) { create(:empty_campaign)} - let(:nonprofit) { empty_campaign.nonprofit} - let(:campaign_with_things_set_1){create(:campaign_with_things_set_1, nonprofit: nonprofit)} - - - context 'when the child is an empty campaign' do - + context "when the child is an empty campaign" do let(:parent_campaign) { campaign_with_things_set_1 } let(:original_campaign_attributes) { empty_campaign.attributes @@ -187,10 +177,9 @@ def get_uploader_attribute_keys end end - context 'when child has something and parent does not' do - + context "when child has something and parent does not" do let(:parent_campaign) { empty_campaign } - let(:child_campaign) {campaign_with_things_set_1 } + let(:child_campaign) { campaign_with_things_set_1 } let(:original_campaign_attributes) { child_campaign.attributes } @@ -225,12 +214,12 @@ def get_uploader_attribute_keys end end - - context 'when child has something and parent has something different' do - + context "when child has something and parent has something different" do let(:parent_campaign) { campaign_with_things_set_1 } - let(:child_campaign) {create(:campaign_with_things_set_2, - parent_campaign_id: parent_campaign.id, nonprofit: parent_campaign.nonprofit)} + let(:child_campaign) { + create(:campaign_with_things_set_2, + parent_campaign_id: parent_campaign.id, nonprofit: parent_campaign.nonprofit) + } let(:original_campaign_attributes) { child_campaign.attributes } @@ -262,12 +251,13 @@ def get_uploader_attribute_keys end end - context 'when child has something and parent has something similar' do - + context "when child has something and parent has something similar" do let(:parent_campaign) { campaign_with_things_set_1 } - let(:child_campaign) {create(:campaign_with_things_set_1, - nonprofit_id: campaign_with_things_set_1.nonprofit.id, - parent_campaign_id: parent_campaign.id, slug: 'another-slug-of-slugs-1')} + let(:child_campaign) { + create(:campaign_with_things_set_1, + nonprofit_id: campaign_with_things_set_1.nonprofit.id, + parent_campaign_id: parent_campaign.id, slug: "another-slug-of-slugs-1") + } let(:original_campaign_attributes) { child_campaign.attributes @@ -302,77 +292,75 @@ def get_uploader_attribute_keys end end - describe ':after_update' do - describe 'with send_campaign_updated' do - let(:parent_campaign) {create(:campaign_with_things_set_1)} - - let!(:child_campaign) {create(:campaign_with_things_set_1, - nonprofit_id: parent_campaign.nonprofit.id, - parent_campaign_id: parent_campaign.id, slug: 'another-slug-of-slugs-1')} + describe ":after_update" do + describe "with send_campaign_updated" do + let(:parent_campaign) { create(:campaign_with_things_set_1) } - let!(:child_campaign_2) {create(:campaign_with_things_set_1, - nonprofit_id: parent_campaign.nonprofit.id, - parent_campaign_id: parent_campaign.id, slug: 'another-slug-of-slugs-2')} + let!(:child_campaign) { + create(:campaign_with_things_set_1, + nonprofit_id: parent_campaign.nonprofit.id, + parent_campaign_id: parent_campaign.id, slug: "another-slug-of-slugs-1") + } + let!(:child_campaign_2) { + create(:campaign_with_things_set_1, + nonprofit_id: parent_campaign.nonprofit.id, + parent_campaign_id: parent_campaign.id, slug: "another-slug-of-slugs-2") + } - it 'queues CampaignUpdatedJob' do + it "queues CampaignUpdatedJob" do expect_job_queued.with(JobTypes::CampaignUpdatedJob, parent_campaign.id) parent_campaign.summary = "a new summary" parent_campaign.save! - end - it 'updates child_campaign' do + it "updates child_campaign" do parent_campaign.summary = "a new summary" parent_campaign.save! child_campaign.reload expect(child_campaign.summary).to eq "a new summary" - - end - it 'updates child_campaign' do + it "updates child_campaign" do parent_campaign.summary = "a new summary" parent_campaign.save! child_campaign_2.reload expect(child_campaign_2.summary).to eq "a new summary" - - end end end - describe '#fee_coverage_option' do - let(:campaign) {build(:campaign, nonprofit: nonprofit)} + describe "#fee_coverage_option" do + let(:campaign) { build(:campaign, nonprofit: nonprofit) } - let(:nonprofit) { build(:nonprofit, fee_coverage_option: 'manual')} + let(:nonprofit) { build(:nonprofit, fee_coverage_option: "manual") } - it 'is set to nonprofit.fee_coverage_option when misc_campaign_info is not there' do - expect(campaign.fee_coverage_option).to eq nonprofit.fee_coverage_option - end + it "is set to nonprofit.fee_coverage_option when misc_campaign_info is not there" do + expect(campaign.fee_coverage_option).to eq nonprofit.fee_coverage_option + end - it 'is set to nonprofit.fee_coverage_option when misc_campaign_info.fee_coverage_option_config is nil' do - campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: nil) - expect(campaign.fee_coverage_option).to eq nonprofit.fee_coverage_option - end + it "is set to nonprofit.fee_coverage_option when misc_campaign_info.fee_coverage_option_config is nil" do + campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: nil) + expect(campaign.fee_coverage_option).to eq nonprofit.fee_coverage_option + end - it 'is set to manual when misc_campaign_info.fee_coverage_option_config is manual' do - campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: 'manual') - expect(campaign.fee_coverage_option).to eq 'manual' - end + it "is set to manual when misc_campaign_info.fee_coverage_option_config is manual" do + campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: "manual") + expect(campaign.fee_coverage_option).to eq "manual" + end - it 'is set to auto when misc_campaign_info.fee_coverage_option_config is auto' do - campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: 'auto') - expect(campaign.fee_coverage_option).to eq 'auto' - end + it "is set to auto when misc_campaign_info.fee_coverage_option_config is auto" do + campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: "auto") + expect(campaign.fee_coverage_option).to eq "auto" + end - it 'is set to none when misc np info fee_coverage_option_config is none' do - campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: 'none') - expect(campaign.fee_coverage_option).to eq 'none' + it "is set to none when misc np info fee_coverage_option_config is none" do + campaign.misc_campaign_info = build(:misc_campaign_info, fee_coverage_option_config: "none") + expect(campaign.fee_coverage_option).to eq "none" + end end end -end diff --git a/spec/models/charge_spec.rb b/spec/models/charge_spec.rb index 183840421..22972c4e9 100644 --- a/spec/models/charge_spec.rb +++ b/spec/models/charge_spec.rb @@ -1,33 +1,34 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe Charge, :type => :model do +RSpec.describe Charge, type: :model do + it { is_expected.to belong_to(:card) } - it {is_expected.to belong_to(:card)} + it { is_expected.to have_many(:manual_balance_adjustments) } - it {is_expected.to have_many( :manual_balance_adjustments)} - - describe '.charge' do + describe ".charge" do include_context :disputes_context - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment: force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} - let(:stripe_dispute) { force_create(:stripe_dispute, stripe_charge_id: charge.stripe_charge_id)} - - it 'directs to a stripe_dispute with the correct Stripe charge id' do + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } + let(:stripe_dispute) { force_create(:stripe_dispute, stripe_charge_id: charge.stripe_charge_id) } + + it "directs to a stripe_dispute with the correct Stripe charge id" do expect(stripe_dispute).to eq charge.stripe_dispute end end - describe '#disbursed?' do - it 'is true when status is disbursed' do - expect(build(:charge, status: 'disbursed')).to be_disbursed + describe "#disbursed?" do + it "is true when status is disbursed" do + expect(build(:charge, status: "disbursed")).to be_disbursed end - it 'is false when status is not disbursed' do - expect(build(:charge, status: 'paid')).to_not be_disbursed + it "is false when status is not disbursed" do + expect(build(:charge, status: "paid")).to_not be_disbursed end end end diff --git a/spec/models/concerns/model/calculated_names_spec.rb b/spec/models/concerns/model/calculated_names_spec.rb index 1ee33f440..bdc96d366 100644 --- a/spec/models/concerns/model/calculated_names_spec.rb +++ b/spec/models/concerns/model/calculated_names_spec.rb @@ -2,17 +2,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe Model::CalculatedNames do - subject do - Class.new do - include Model::CalculatedNames + subject do + Class.new do + include Model::CalculatedNames - attr_accessor :name + attr_accessor :name + end.new + end - end.new - end - - it_behaves_like 'a model with a calculated first and last name' + it_behaves_like "a model with a calculated first and last name" end diff --git a/spec/models/concerns/model/houidable_spec.rb b/spec/models/concerns/model/houidable_spec.rb index 0e8773e28..d75a430a0 100644 --- a/spec/models/concerns/model/houidable_spec.rb +++ b/spec/models/concerns/model/houidable_spec.rb @@ -2,212 +2,212 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" # rubocop:disable RSpec/VerifiedDoubles, RSpec/MessageSpies regular doubles work fine in this use-case RSpec.describe Model::Houidable do - let(:houid_test_class) do - Class.new do - include ActiveModel::AttributeAssignment - include ActiveModel::Model - extend ActiveModel::Callbacks - include Model::Houidable - - attr_accessor :id, :houid_id - - define_model_callbacks :initialize - def initialize(attributes = {}) - run_callbacks :initialize do - assign_attributes(attributes) - end - end - - # mock for read and write attributes - def read_attribute(attr_name) - send(attr_name.to_sym) - end - - def write_attribute(attr_name, value) - send("#{attr_name}=".to_sym, value) - end - end - end - - context 'when using the default :id attribute' do - let(:test_class) do - Class.new(houid_test_class) do - setup_houid :trxassign - end - end - - let(:with_before_set_callback) do - Class.new(test_class) do - mattr_accessor :callback_handler - before_houid_set ->(model) { self.class.callback_handler.before_houid_set_callback(model) } - end - end - - let(:with_after_set_callback) do - Class.new(test_class) do - mattr_accessor :callback_handler - after_houid_set ->(model) { self.class.callback_handler.after_houid_set_callback(model) } - end - end - - let(:prefix) { :trxassign } - let(:preset_houid) { 'test_eoiathotih' } - - let(:default_trxassign) { test_class.new } - - let(:already_set_houid) { test_class.new(id: preset_houid) } - - describe '#houid_prefix' do - it 'is the one passed' do - expect(default_trxassign.houid_prefix).to eq prefix - end - end - - describe '.houid_prefix' do - it 'is the one passed at class level' do - expect(test_class.houid_prefix).to eq prefix - end - end - - describe '#generate_houid' do - it 'generates a valid houid' do - expect(default_trxassign.generate_houid).to match_houid(prefix) - end - end - - describe '.generate_houid' do - it 'generates a valid houid at class level' do - expect(test_class.generate_houid).to match_houid(prefix) - end - end - - describe '#houid_attribute' do - it 'returns the default of :id' do - expect(default_trxassign.houid_attribute).to eq :id - end - end - - describe '.houid_attribute' do - it 'returns the default of :id' do - expect(test_class.houid_attribute).to eq :id - end - end - - it 'sets a valid houid as id' do - expect(default_trxassign.id).to match_houid(prefix) - end - - it 'will not override an id if already set' do - expect(already_set_houid.id).to eq preset_houid - end - - it 'fires the before_houid_set callback' do - with_before_set_callback.callback_handler = double('Before Callback Handler') - expect(with_before_set_callback.callback_handler).to receive(:before_houid_set_callback).with( - having_attributes(id: nil) - ) - with_before_set_callback.new - end - - it 'fires the after_houid_set callback' do - with_after_set_callback.callback_handler = double('After Callback Handler') - expect(with_after_set_callback.callback_handler).to receive(:after_houid_set_callback).with( - having_attributes(id: match_houid(:trxassign)) - ) - with_after_set_callback.new - end - end - - context 'when using a custom attribute' do - let(:test_class) do - Class.new(houid_test_class) do - setup_houid 'trxassign', 'houid_id' - end - end - - let(:with_before_set_callback) do - Class.new(test_class) do - mattr_accessor :callback_handler - before_houid_set ->(model) { self.class.callback_handler.before_houid_set_callback(model) } - end - end - - let(:with_after_set_callback) do - Class.new(test_class) do - mattr_accessor :callback_handler - after_houid_set ->(model) { self.class.callback_handler.after_houid_set_callback(model) } - end - end - - let(:prefix) { :trxassign } - let(:preset_houid) { 'test_eoiathotih' } - - let(:default_trxassign) { test_class.new } - - let(:already_set_houid) { test_class.new(houid_id: preset_houid) } - - describe '#houid_prefix' do - it 'is the one passed' do - expect(default_trxassign.houid_prefix).to eq prefix - end - end - - describe '.houid_prefix' do - it 'is the one passed at class level' do - expect(test_class.houid_prefix).to eq prefix - end - end - - describe '#generate_houid' do - it 'generates a valid houid' do - expect(default_trxassign.generate_houid).to match_houid(prefix) - end - end - - describe '.generate_houid' do - it 'generates a valid houid at class level' do - expect(test_class.generate_houid).to match_houid(prefix) - end - end - - describe '#houid_attribute' do - it 'returns the default of :houid_id' do - expect(default_trxassign.houid_attribute).to eq :houid_id - end - end - - describe '.houid_attribute' do - it 'returns the passed value of :houid_id' do - expect(test_class.houid_attribute).to eq :houid_id - end - end - - it 'sets a valid houid as id' do - expect(default_trxassign.houid_id).to match_houid(prefix) - end - - it 'will not override an id if already set' do - expect(already_set_houid.houid_id).to eq preset_houid - end - - it 'fires the before_houid_set callback' do - with_before_set_callback.callback_handler = double('Before Callback Handler') # rubocop:disable RSpec/VerifiedDoubles - expect(with_before_set_callback.callback_handler).to receive(:before_houid_set_callback).with( - having_attributes(houid_id: nil) - ) - with_before_set_callback.new - end - - it 'fires the after_houid_set callback' do - with_after_set_callback.callback_handler = double('After Callback Handler') # rubocop:disable RSpec/VerifiedDoubles - expect(with_after_set_callback.callback_handler).to receive(:after_houid_set_callback).with( - having_attributes(houid_id: match_houid(:trxassign)) - ) - with_after_set_callback.new - end - end + let(:houid_test_class) do + Class.new do + include ActiveModel::AttributeAssignment + include ActiveModel::Model + extend ActiveModel::Callbacks + include Model::Houidable + + attr_accessor :id, :houid_id + + define_model_callbacks :initialize + def initialize(attributes = {}) + run_callbacks :initialize do + assign_attributes(attributes) + end + end + + # mock for read and write attributes + def read_attribute(attr_name) + send(attr_name.to_sym) + end + + def write_attribute(attr_name, value) + send(:"#{attr_name}=", value) + end + end + end + + context "when using the default :id attribute" do + let(:test_class) do + Class.new(houid_test_class) do + setup_houid :trxassign + end + end + + let(:with_before_set_callback) do + Class.new(test_class) do + mattr_accessor :callback_handler + before_houid_set ->(model) { self.class.callback_handler.before_houid_set_callback(model) } + end + end + + let(:with_after_set_callback) do + Class.new(test_class) do + mattr_accessor :callback_handler + after_houid_set ->(model) { self.class.callback_handler.after_houid_set_callback(model) } + end + end + + let(:prefix) { :trxassign } + let(:preset_houid) { "test_eoiathotih" } + + let(:default_trxassign) { test_class.new } + + let(:already_set_houid) { test_class.new(id: preset_houid) } + + describe "#houid_prefix" do + it "is the one passed" do + expect(default_trxassign.houid_prefix).to eq prefix + end + end + + describe ".houid_prefix" do + it "is the one passed at class level" do + expect(test_class.houid_prefix).to eq prefix + end + end + + describe "#generate_houid" do + it "generates a valid houid" do + expect(default_trxassign.generate_houid).to match_houid(prefix) + end + end + + describe ".generate_houid" do + it "generates a valid houid at class level" do + expect(test_class.generate_houid).to match_houid(prefix) + end + end + + describe "#houid_attribute" do + it "returns the default of :id" do + expect(default_trxassign.houid_attribute).to eq :id + end + end + + describe ".houid_attribute" do + it "returns the default of :id" do + expect(test_class.houid_attribute).to eq :id + end + end + + it "sets a valid houid as id" do + expect(default_trxassign.id).to match_houid(prefix) + end + + it "will not override an id if already set" do + expect(already_set_houid.id).to eq preset_houid + end + + it "fires the before_houid_set callback" do + with_before_set_callback.callback_handler = double("Before Callback Handler") + expect(with_before_set_callback.callback_handler).to receive(:before_houid_set_callback).with( + having_attributes(id: nil) + ) + with_before_set_callback.new + end + + it "fires the after_houid_set callback" do + with_after_set_callback.callback_handler = double("After Callback Handler") + expect(with_after_set_callback.callback_handler).to receive(:after_houid_set_callback).with( + having_attributes(id: match_houid(:trxassign)) + ) + with_after_set_callback.new + end + end + + context "when using a custom attribute" do + let(:test_class) do + Class.new(houid_test_class) do + setup_houid "trxassign", "houid_id" + end + end + + let(:with_before_set_callback) do + Class.new(test_class) do + mattr_accessor :callback_handler + before_houid_set ->(model) { self.class.callback_handler.before_houid_set_callback(model) } + end + end + + let(:with_after_set_callback) do + Class.new(test_class) do + mattr_accessor :callback_handler + after_houid_set ->(model) { self.class.callback_handler.after_houid_set_callback(model) } + end + end + + let(:prefix) { :trxassign } + let(:preset_houid) { "test_eoiathotih" } + + let(:default_trxassign) { test_class.new } + + let(:already_set_houid) { test_class.new(houid_id: preset_houid) } + + describe "#houid_prefix" do + it "is the one passed" do + expect(default_trxassign.houid_prefix).to eq prefix + end + end + + describe ".houid_prefix" do + it "is the one passed at class level" do + expect(test_class.houid_prefix).to eq prefix + end + end + + describe "#generate_houid" do + it "generates a valid houid" do + expect(default_trxassign.generate_houid).to match_houid(prefix) + end + end + + describe ".generate_houid" do + it "generates a valid houid at class level" do + expect(test_class.generate_houid).to match_houid(prefix) + end + end + + describe "#houid_attribute" do + it "returns the default of :houid_id" do + expect(default_trxassign.houid_attribute).to eq :houid_id + end + end + + describe ".houid_attribute" do + it "returns the passed value of :houid_id" do + expect(test_class.houid_attribute).to eq :houid_id + end + end + + it "sets a valid houid as id" do + expect(default_trxassign.houid_id).to match_houid(prefix) + end + + it "will not override an id if already set" do + expect(already_set_houid.houid_id).to eq preset_houid + end + + it "fires the before_houid_set callback" do + with_before_set_callback.callback_handler = double("Before Callback Handler") # rubocop:disable RSpec/VerifiedDoubles + expect(with_before_set_callback.callback_handler).to receive(:before_houid_set_callback).with( + having_attributes(houid_id: nil) + ) + with_before_set_callback.new + end + + it "fires the after_houid_set callback" do + with_after_set_callback.callback_handler = double("After Callback Handler") # rubocop:disable RSpec/VerifiedDoubles + expect(with_after_set_callback.callback_handler).to receive(:after_houid_set_callback).with( + having_attributes(houid_id: match_houid(:trxassign)) + ) + with_after_set_callback.new + end + end end # rubocop:enable RSpec/VerifiedDoubles, RSpec/MessageSpies diff --git a/spec/models/dispute_spec.rb b/spec/models/dispute_spec.rb index 0a829980c..ba6d77e9f 100644 --- a/spec/models/dispute_spec.rb +++ b/spec/models/dispute_spec.rb @@ -1,76 +1,78 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe Dispute, :type => :model do - it {is_expected.to have_one(:stripe_dispute).with_primary_key(:stripe_dispute_id).with_foreign_key(:stripe_dispute_id)} - it {is_expected.to belong_to(:charge)} - it {is_expected.to have_many(:dispute_transactions).order('date ASC')} +RSpec.describe Dispute, type: :model do + it { is_expected.to have_one(:stripe_dispute).with_primary_key(:stripe_dispute_id).with_foreign_key(:stripe_dispute_id) } + it { is_expected.to belong_to(:charge) } + it { is_expected.to have_many(:dispute_transactions).order("date ASC") } - it {is_expected.to have_one(:supporter).through(:charge)} - it {is_expected.to have_one(:nonprofit).through(:charge)} - it {is_expected.to have_one(:original_payment).through(:charge).source(:payment)} + it { is_expected.to have_one(:supporter).through(:charge) } + it { is_expected.to have_one(:nonprofit).through(:charge) } + it { is_expected.to have_one(:original_payment).through(:charge).source(:payment) } - it {is_expected.to have_many(:activities)} + it { is_expected.to have_many(:activities) } - describe '.charge' do + describe ".charge" do include_context :disputes_context - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} - let!(:obj) { force_create(:stripe_dispute, stripe_charge_id: charge.stripe_charge_id)} - it 'directs to a stripe_dispute with the correct Stripe dispute id' do + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } + let!(:obj) { force_create(:stripe_dispute, stripe_charge_id: charge.stripe_charge_id) } + it "directs to a stripe_dispute with the correct Stripe dispute id" do expect(dispute.stripe_dispute).to eq obj end end - describe '.activities' do + describe ".activities" do shared_context :common_specs do - let(:activity_json) { activity.json_data} - specify { expect(activity.supporter).to eq supporter} - specify { expect(activity.nonprofit).to eq nonprofit} - specify { expect(activity_json['status']).to eq dispute.status } - specify { expect(activity_json['reason']).to eq dispute.reason } - specify { expect(activity_json['original_id']).to eq charge.payment.id} - specify { expect(activity_json['original_kind']).to eq charge.payment.kind} - specify { expect(activity_json['original_gross_amount']).to eq charge.payment.gross_amount} - specify { expect(activity_json['original_date']).to eq charge.payment.date} - specify { expect(activity_json['gross_amount']).to eq dispute.gross_amount} + let(:activity_json) { activity.json_data } + specify { expect(activity.supporter).to eq supporter } + specify { expect(activity.nonprofit).to eq nonprofit } + specify { expect(activity_json["status"]).to eq dispute.status } + specify { expect(activity_json["reason"]).to eq dispute.reason } + specify { expect(activity_json["original_id"]).to eq charge.payment.id } + specify { expect(activity_json["original_kind"]).to eq charge.payment.kind } + specify { expect(activity_json["original_gross_amount"]).to eq charge.payment.gross_amount } + specify { expect(activity_json["original_date"]).to eq charge.payment.date } + specify { expect(activity_json["gross_amount"]).to eq dispute.gross_amount } end describe "dispute.created" do include_context :common_specs include_context :dispute_created_context - - let(:obj) { StripeDispute.create(object:json) } - let(:activity) { dispute.activities.build('DisputeCreated', Time.at(event_json.created))} - specify { expect(activity.kind).to eq 'DisputeCreated'} - specify { expect(activity.date).to eq Time.at(event_json.created)} + let(:obj) { StripeDispute.create(object: json) } + let(:activity) { dispute.activities.build("DisputeCreated", Time.at(event_json.created)) } + + specify { expect(activity.kind).to eq "DisputeCreated" } + specify { expect(activity.date).to eq Time.at(event_json.created) } end describe "dispute.won" do include_context :common_specs include_context :dispute_won_context - - let(:obj) { StripeDispute.create(object:json) } - let(:activity) { dispute.activities.build('DisputeWon', Time.at(event_json.created)) } - specify { expect(activity.kind).to eq 'DisputeWon' } + let(:obj) { StripeDispute.create(object: json) } + let(:activity) { dispute.activities.build("DisputeWon", Time.at(event_json.created)) } + + specify { expect(activity.kind).to eq "DisputeWon" } specify { expect(activity.date).to eq Time.at(event_json.created) } end describe "dispute.lost" do include_context :common_specs include_context :dispute_lost_context - - let(:obj) { StripeDispute.create(object:json) } - let(:activity) { obj.dispute.activities.build('DisputeLost', Time.at(event_json.created))} - specify { expect(activity.kind).to eq 'DisputeLost'} - specify { expect(activity_json['gross_amount']).to eq dispute.gross_amount} - specify { expect(activity.date).to eq Time.at(event_json.created)} + let(:obj) { StripeDispute.create(object: json) } + let(:activity) { obj.dispute.activities.build("DisputeLost", Time.at(event_json.created)) } + + specify { expect(activity.kind).to eq "DisputeLost" } + specify { expect(activity_json["gross_amount"]).to eq dispute.gross_amount } + specify { expect(activity.date).to eq Time.at(event_json.created) } end end end diff --git a/spec/models/dispute_transaction_spec.rb b/spec/models/dispute_transaction_spec.rb index 1fe7e169b..12085840c 100644 --- a/spec/models/dispute_transaction_spec.rb +++ b/spec/models/dispute_transaction_spec.rb @@ -1,20 +1,20 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe DisputeTransaction, :type => :model do - it {is_expected.to belong_to(:dispute)} - it {is_expected.to belong_to(:payment)} +RSpec.describe DisputeTransaction, type: :model do + it { is_expected.to belong_to(:dispute) } + it { is_expected.to belong_to(:payment) } it { is_expected.to have_one(:nonprofit).through(:dispute) } it { is_expected.to have_one(:supporter).through(:dispute) } - it {is_expected.to have_many( :manual_balance_adjustments)} + it { is_expected.to have_many(:manual_balance_adjustments) } describe "#from_donation?" do - it 'is true when dispute_transaction is associated with a donation' do + it "is true when dispute_transaction is associated with a donation" do expect(build(:dispute_transaction, :from_donation).from_donation?).to eq true end - it 'is true when dispute_transaction is not associated with a donation' do + it "is true when dispute_transaction is not associated with a donation" do expect(build(:dispute_transaction, :not_from_donation).from_donation?).to eq false end end diff --git a/spec/models/disputes/case.rb b/spec/models/disputes/case.rb index b01691d1b..1e6d3f223 100644 --- a/spec/models/disputes/case.rb +++ b/spec/models/disputes/case.rb @@ -20,10 +20,9 @@ def supporter @supporter ||= create(:supporter_base) end - def stripe_dispute event_json = dispute_on_stripe - @stripe_dispute ||= StripeDispute.create(object: event_json['data']['object']) + @stripe_dispute ||= StripeDispute.create(object: event_json["data"]["object"]) end def legacy_dispute @@ -62,8 +61,6 @@ def transaction_payment_withdrawal transaction_to_be_disputed.ordered_payments.first when 3 transaction_to_be_disputed.ordered_payments.second - else - nil end end @@ -71,13 +68,11 @@ def transaction_payment_reinstated transaction_to_be_disputed.reload case transaction_to_be_disputed.ordered_payments.count when 3 - transaction_to_be_disputed.ordered_payments.first - else - nil + transaction_to_be_disputed.ordered_payments.first end end - def events(types:[]) + def events(types: []) nonprofit.associated_object_events.event_types(types).page end diff --git a/spec/models/donation_spec.rb b/spec/models/donation_spec.rb index 9ced771e4..bb332d2f7 100644 --- a/spec/models/donation_spec.rb +++ b/spec/models/donation_spec.rb @@ -1,28 +1,27 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - -RSpec.describe Donation, :type => :model do +require "rails_helper" +RSpec.describe Donation, type: :model do it { is_expected.to have_many(:modern_donations) } describe "#campaign_gift_purchase?" do - it 'is false without any campaign_gifts' do + it "is false without any campaign_gifts" do expect(build(:donation)).to_not be_campaign_gift_purchase end - it 'is true with campaign_gifts' do + it "is true with campaign_gifts" do expect(build(:donation, campaign_gifts: [build(:campaign_gift)])).to be_campaign_gift_purchase end end describe "#actual_donation?" do - it 'is true without any campaign_gifts' do + it "is true without any campaign_gifts" do expect(build(:donation)).to be_actual_donation end - it 'is false with campaign_gifts' do + it "is false with campaign_gifts" do expect(build(:donation, campaign_gifts: [build(:campaign_gift)])).to_not be_actual_donation end end diff --git a/spec/models/drip_email_list_spec.rb b/spec/models/drip_email_list_spec.rb index 62e8c4720..a3f80a40a 100644 --- a/spec/models/drip_email_list_spec.rb +++ b/spec/models/drip_email_list_spec.rb @@ -1,19 +1,18 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe DripEmailList, type: :model do - - describe '#list_path' do - it 'is correctly generated' do + describe "#list_path" do + it "is correctly generated" do email_list = build_stubbed(:drip_email_list_base) - expect(email_list.list_path).to eq "lists/"+ email_list.mailchimp_list_id + expect(email_list.list_path).to eq "lists/" + email_list.mailchimp_list_id end end - describe '#list_members_path' do - it 'is correctly generated' do + describe "#list_members_path" do + it "is correctly generated" do email_list = build_stubbed(:drip_email_list_base) - expect(email_list.list_members_path).to eq "lists/"+ email_list.mailchimp_list_id + "/members" + expect(email_list.list_members_path).to eq "lists/" + email_list.mailchimp_list_id + "/members" end end end diff --git a/spec/models/e_tap_import_contact_spec.rb b/spec/models/e_tap_import_contact_spec.rb index a2d11e177..eca64010e 100644 --- a/spec/models/e_tap_import_contact_spec.rb +++ b/spec/models/e_tap_import_contact_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe ETapImportContact, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/e_tap_import_journal_entry_spec.rb b/spec/models/e_tap_import_journal_entry_spec.rb index 889ebb833..7ae03e01a 100644 --- a/spec/models/e_tap_import_journal_entry_spec.rb +++ b/spec/models/e_tap_import_journal_entry_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe ETapImportJournalEntry, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/e_tap_import_spec.rb b/spec/models/e_tap_import_spec.rb index 8fc3107fa..665d714df 100644 --- a/spec/models/e_tap_import_spec.rb +++ b/spec/models/e_tap_import_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe ETapImport, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/email_customization_spec.rb b/spec/models/email_customization_spec.rb index 580b6fb85..3649e34d2 100644 --- a/spec/models/email_customization_spec.rb +++ b/spec/models/email_customization_spec.rb @@ -1,14 +1,14 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe EmailCustomization, type: :model do - it {is_expected.to have_db_column(:contents)} - it {is_expected.to validate_presence_of(:contents)} + it { is_expected.to have_db_column(:contents) } + it { is_expected.to validate_presence_of(:contents) } - it {is_expected.to have_db_column(:name)} - it {is_expected.to have_db_index(:name)} - it {is_expected.to validate_presence_of(:name)} + it { is_expected.to have_db_column(:name) } + it { is_expected.to have_db_index(:name) } + it { is_expected.to validate_presence_of(:name) } - it {is_expected.to belong_to(:nonprofit).required(true)} - it {is_expected.to have_db_index(:nonprofit_id)} + it { is_expected.to belong_to(:nonprofit).required(true) } + it { is_expected.to have_db_index(:nonprofit_id) } end diff --git a/spec/models/email_list_spec.rb b/spec/models/email_list_spec.rb index 587a7fcd6..53ee274a1 100644 --- a/spec/models/email_list_spec.rb +++ b/spec/models/email_list_spec.rb @@ -1,112 +1,110 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe EmailList, :type => :model do +RSpec.describe EmailList, type: :model do it { is_expected.to belong_to(:nonprofit) } it { is_expected.to belong_to(:tag_master) } - - describe '#api_key' do + describe "#api_key" do it "retrieves the api key properly" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, :without_base_uri, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) + email_list = create(:email_list_base, :without_base_uri, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) expect(Mailchimp).to receive(:get_mailchimp_token).with(nonprofit.id).and_return("a-key") expect(email_list.api_key).to eq "a-key" end end - describe '#base_uri' do + describe "#base_uri" do it "retrieves the base_uri properly" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, :without_base_uri, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) + email_list = create(:email_list_base, :without_base_uri, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) expect(Mailchimp).to receive(:get_mailchimp_token).with(nonprofit.id).and_return("a-key") - expect(Mailchimp).to receive(:base_uri).with('a-key').and_return('https://us3.api.mailchimp.com/3.0') + expect(Mailchimp).to receive(:base_uri).with("a-key").and_return("https://us3.api.mailchimp.com/3.0") - expect(email_list.base_uri).to eq 'https://us3.api.mailchimp.com/3.0' + expect(email_list.base_uri).to eq "https://us3.api.mailchimp.com/3.0" end - it 'caches the base_uri' do - + it "caches the base_uri" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, :without_base_uri, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) + email_list = create(:email_list_base, :without_base_uri, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) expect(Mailchimp).to receive(:get_mailchimp_token).with(nonprofit.id).and_return("a-key").twice - expect(Mailchimp).to receive(:base_uri).with('a-key').and_return('https://us3.api.mailchimp.com/3.0').twice + expect(Mailchimp).to receive(:base_uri).with("a-key").and_return("https://us3.api.mailchimp.com/3.0").twice - expect(email_list.base_uri).to eq 'https://us3.api.mailchimp.com/3.0' + expect(email_list.base_uri).to eq "https://us3.api.mailchimp.com/3.0" - expect(email_list.base_uri).to eq 'https://us3.api.mailchimp.com/3.0' + expect(email_list.base_uri).to eq "https://us3.api.mailchimp.com/3.0" email_list.base_uri = nil - expect(email_list.base_uri).to eq 'https://us3.api.mailchimp.com/3.0' + expect(email_list.base_uri).to eq "https://us3.api.mailchimp.com/3.0" end end - describe '#list_url' do - it 'returns the proper url' do + describe "#list_url" do + it "returns the proper url" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) - + email_list = create(:email_list_base, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) + expect(email_list.list_url).to eq "https://us3.api.mailchimp.com/3.0/lists/#{email_list.mailchimp_list_id}" end end - describe '#list_members_url' do - it 'returns the proper url' do + describe "#list_members_url" do + it "returns the proper url" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) + email_list = create(:email_list_base, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) expect(email_list).to receive(:base_uri).and_return("https://us3.api.mailchimp.com/3.0") - + expect(email_list.list_members_url).to eq "https://us3.api.mailchimp.com/3.0/lists/#{email_list.mailchimp_list_id}/members" end end - describe '#populate_list_later' do - it 'queues a PopulateListJob' do + describe "#populate_list_later" do + it "queues a PopulateListJob" do ActiveJob::Base.queue_adapter = :test nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) - expect{email_list.populate_list_later}.to have_enqueued_job(PopulateListJob).with(email_list) + email_list = create(:email_list_base, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) + expect { email_list.populate_list_later }.to have_enqueued_job(PopulateListJob).with(email_list) end end - describe '#deleted?' do - it 'is false if tag_master is marked as not deleted' do + describe "#deleted?" do + it "is false if tag_master is marked as not deleted" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit)) + email_list = create(:email_list_base, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit)) expect(email_list).to_not be_deleted - end + end - it 'is true if tag_master is marked as deleted' do + it "is true if tag_master is marked as deleted" do nonprofit = build(:nonprofit_base) - email_list = create(:email_list_base, nonprofit:nonprofit, tag_master:build(:tag_master_base, nonprofit:nonprofit, deleted:true)) + email_list = create(:email_list_base, nonprofit: nonprofit, tag_master: build(:tag_master_base, nonprofit: nonprofit, deleted: true)) expect(email_list).to be_deleted - end + end end - describe '#list_path' do - it 'is correctly generated' do + describe "#list_path" do + it "is correctly generated" do email_list = build_stubbed(:email_list_base) - expect(email_list.list_path).to eq "lists/"+ email_list.mailchimp_list_id + expect(email_list.list_path).to eq "lists/" + email_list.mailchimp_list_id end end - describe '#list_members_path' do - it 'is correctly generated' do + describe "#list_members_path" do + it "is correctly generated" do email_list = build_stubbed(:email_list_base) - expect(email_list.list_members_path).to eq "lists/"+ email_list.mailchimp_list_id + "/members" + expect(email_list.list_members_path).to eq "lists/" + email_list.mailchimp_list_id + "/members" end end describe "#populate_list" do - #from insert_email_lists_spec.rb - let(:np) { create(:nonprofit_base)} - let(:tag_master) {force_create(:tag_master, nonprofit: np)} - let(:email_list) {force_create(:email_list, mailchimp_list_id: 'list_id', tag_master: tag_master, nonprofit:np, list_name: "temp")} - let(:supporter) { force_create(:supporter, nonprofit:np, email: 'on_local@email.com', name: 'Penelope Rebecca Schultz')} - let(:tag_join) {force_create(:tag_join, tag_master: tag_master, supporter: supporter)} + # from insert_email_lists_spec.rb + let(:np) { create(:nonprofit_base) } + let(:tag_master) { force_create(:tag_master, nonprofit: np) } + let(:email_list) { force_create(:email_list, mailchimp_list_id: "list_id", tag_master: tag_master, nonprofit: np, list_name: "temp") } + let(:supporter) { force_create(:supporter, nonprofit: np, email: "on_local@email.com", name: "Penelope Rebecca Schultz") } + let(:tag_join) { force_create(:tag_join, tag_master: tag_master, supporter: supporter) } def setup ActiveJob::Base.queue_adapter = :test @@ -115,20 +113,18 @@ def setup tag_join end - it 'populates with all of the supporters on list one' do + it "populates with all of the supporters on list one" do setup - expect(Mailchimp).to receive(:perform_batch_operations).with(np.id, - a_collection_including( - an_instance_of(MailchimpBatchOperation).and have_attributes(method: 'POST', list: email_list, supporter: supporter) - )) + expect(Mailchimp).to receive(:perform_batch_operations).with(np.id, + a_collection_including( + an_instance_of(MailchimpBatchOperation).and(have_attributes(method: "POST", list: email_list, supporter: supporter)) + )) email_list.populate_list end - - - it 'does nothing if #deleted?' do + it "does nothing if #deleted?" do setup - email_list.tag_master.update(deleted:true) + email_list.tag_master.update(deleted: true) expect(Mailchimp).to_not receive(:perform_batch_operations) email_list.populate_list end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index e219ea089..dfb73268f 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -1,8 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - -RSpec.describe Event, :type => :model do - - it {is_expected.to have_many(:ticketholders).through(:tickets).source(:supporter)} +require "rails_helper" +RSpec.describe Event, type: :model do + it { is_expected.to have_many(:ticketholders).through(:tickets).source(:supporter) } end diff --git a/spec/models/export_format_spec.rb b/spec/models/export_format_spec.rb index a93c097bd..b959bc8c1 100644 --- a/spec/models/export_format_spec.rb +++ b/spec/models/export_format_spec.rb @@ -1,23 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe ExportFormat, type: :model do let(:nonprofit) { force_create(:fv_poverty) } - describe '#validation' do + describe "#validation" do let(:attributes) do { - 'name' => 'CiviCRM format', - 'date_format' => 'MM/DD/YYYY', - 'show_currency' => false, - 'custom_columns_and_values' => { - 'payments.kind' => { - 'custom_values' => { - 'RecurringDonation' => 'Recurring Donation' + "name" => "CiviCRM format", + "date_format" => "MM/DD/YYYY", + "show_currency" => false, + "custom_columns_and_values" => { + "payments.kind" => { + "custom_values" => { + "RecurringDonation" => "Recurring Donation" } }, - 'payments.date' => { - 'custom_name' => 'Payment Date' + "payments.date" => { + "custom_name" => "Payment Date" } } } @@ -25,114 +25,114 @@ subject { nonprofit.export_formats.create(attributes) } - it 'is valid' do + it "is valid" do expect(subject.valid?).to be_truthy end - context 'when it does not include a name' do + context "when it does not include a name" do before do - attributes.delete('name') + attributes.delete("name") end - it 'is invalid' do + it "is invalid" do expect(subject.valid?).to be_falsy end end - context 'when custom_columns_and_values does not follow expected format' do - context 'when it tries to customize a column that is not allowed' do + context "when custom_columns_and_values does not follow expected format" do + context "when it tries to customize a column that is not allowed" do before do - attributes['custom_columns_and_values']['donations.dedication'] = { - 'custom_name' => 'Dedicated to' + attributes["custom_columns_and_values"]["donations.dedication"] = { + "custom_name" => "Dedicated to" } end - it 'is invalid' do + it "is invalid" do expect(subject.valid?).to be_falsy end end - context 'when it tries to customize a value from a column that is not supported' do + context "when it tries to customize a value from a column that is not supported" do before do - attributes['custom_columns_and_values']['offsite_payments.check_number'] = { - 'custom_values' => { - '1234' => '12345' + attributes["custom_columns_and_values"]["offsite_payments.check_number"] = { + "custom_values" => { + "1234" => "12345" } } end - it 'is invalid' do + it "is invalid" do expect(subject.valid?).to be_falsy end end - context 'when a customization does not specify a custom_value or custom_name' do + context "when a customization does not specify a custom_value or custom_name" do before do - attributes['custom_columns_and_values']['payments.kind'] = { - 'kind' => 'Type' + attributes["custom_columns_and_values"]["payments.kind"] = { + "kind" => "Type" } end - it 'is invalid' do + it "is invalid" do expect(subject.valid?).to be_falsy end end end - context 'when date_format is not provided' do + context "when date_format is not provided" do let(:attributes) do { - 'name' => 'CiviCRM format', - 'show_currency' => false + "name" => "CiviCRM format", + "show_currency" => false } end - it 'is valid' do + it "is valid" do expect(subject.valid?).to be_truthy end end - context 'when date_format contains invalid separator' do + context "when date_format contains invalid separator" do let(:attributes) do { - 'name' => 'CiviCRM format', - 'date_format' => "HH'mm" + "name" => "CiviCRM format", + "date_format" => "HH'mm" } end - it 'is invalid' do + it "is invalid" do expect(subject.valid?).to be_falsy end end - context 'when date_format contains invalid pattern' do + context "when date_format contains invalid pattern" do let(:attributes) do { - 'name' => 'CiviCRM format', - 'date_format' => "HH:mm seconds" + "name" => "CiviCRM format", + "date_format" => "HH:mm seconds" } end - it 'is invalid' do + it "is invalid" do expect(subject.valid?).to be_falsy end end end - describe '#after_validation' do + describe "#after_validation" do let(:attributes) do { - 'name' => 'CiviCRM format', - 'date_format' => 'MM/DD/YYYY', - 'show_currency' => false, - 'custom_columns_and_values' => { - 'payments.kind' => { - 'custom_values' => { - 'RecurringDonation' => 'Recurring Donation' + "name" => "CiviCRM format", + "date_format" => "MM/DD/YYYY", + "show_currency" => false, + "custom_columns_and_values" => { + "payments.kind" => { + "custom_values" => { + "RecurringDonation" => "Recurring Donation" } }, - 'payments.date' => { - 'custom_name' => 'Payment Date' + "payments.date" => { + "custom_name" => "Payment Date" } } } @@ -140,8 +140,8 @@ subject { nonprofit.export_formats.create(attributes) } - it 'adds double quote to custom_name' do - expect(subject.custom_columns_and_values['payments.date']['custom_name']) + it "adds double quote to custom_name" do + expect(subject.custom_columns_and_values["payments.date"]["custom_name"]) .to eq('"Payment Date"') end end diff --git a/spec/models/fee_coverage_detail_base_spec.rb b/spec/models/fee_coverage_detail_base_spec.rb index a63961b81..f9deada60 100644 --- a/spec/models/fee_coverage_detail_base_spec.rb +++ b/spec/models/fee_coverage_detail_base_spec.rb @@ -1,7 +1,7 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe FeeCoverageDetailBase, type: :model do - context 'validation' do - it {is_expected.to belong_to(:fee_era).validate(true)} + context "validation" do + it { is_expected.to belong_to(:fee_era).validate(true) } end end diff --git a/spec/models/fee_era_spec.rb b/spec/models/fee_era_spec.rb index a265ecd9b..af5f9c0a8 100644 --- a/spec/models/fee_era_spec.rb +++ b/spec/models/fee_era_spec.rb @@ -1,68 +1,67 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe FeeEra, type: :model do include_context "Stripe::Source doubles" around(:each) do |example| - Timecop.freeze(2020,5, 4) do + Timecop.freeze(2020, 5, 4) do example.run end end - describe '.current' do - context 'when era exists' do - let!(:fee_era) { create(:fee_era)} - let!(:fee_era_with_no_start) { create(:fee_era_with_no_start)} - let!(:fee_era_with_no_end) { create(:fee_era_with_no_end)} + describe ".current" do + context "when era exists" do + let!(:fee_era) { create(:fee_era) } + let!(:fee_era_with_no_start) { create(:fee_era_with_no_start) } + let!(:fee_era_with_no_end) { create(:fee_era_with_no_end) } it "for current time" do - expect(FeeEra.current).to eq fee_era + expect(FeeEra.current).to eq fee_era end end - - context 'when no era is found' do + + context "when no era is found" do it { - expect { FeeEra.current}.to raise_error(ActiveRecord::RecordNotFound) + expect { FeeEra.current }.to raise_error(ActiveRecord::RecordNotFound) } end end - - describe '.find_by_time' do - context 'when era exists' do - let!(:fee_era) { create(:fee_era)} - let!(:fee_era_with_no_start) { create(:fee_era_with_no_start)} - let!(:fee_era_with_no_end) { create(:fee_era_with_no_end)} + + describe ".find_by_time" do + context "when era exists" do + let!(:fee_era) { create(:fee_era) } + let!(:fee_era_with_no_start) { create(:fee_era_with_no_start) } + let!(:fee_era_with_no_end) { create(:fee_era_with_no_end) } it "for current time" do - expect(FeeEra.find_by_time).to eq fee_era + expect(FeeEra.find_by_time).to eq fee_era end - it 'for passed time during current era' do + it "for passed time during current era" do expect(FeeEra.find_by_time(Time.new(2020, 5, 3))).to eq fee_era end - it 'for passed time far in past' do + it "for passed time far in past" do expect(FeeEra.find_by_time(Time.new(2019, 5, 4))).to eq fee_era_with_no_start end - it 'for passed time at the beginning of last era' do + it "for passed time at the beginning of last era" do expect(FeeEra.find_by_time(Time.new(2020, 5, 7))).to eq fee_era_with_no_end end - it 'for passed time far in future' do + it "for passed time far in future" do expect(FeeEra.find_by_time(Time.new(2100, 5, 4))).to eq fee_era_with_no_end end end - context 'when no era is found' do + context "when no era is found" do it { - expect { FeeEra.find_by_time}.to raise_error(ActiveRecord::RecordNotFound) + expect { FeeEra.find_by_time }.to raise_error(ActiveRecord::RecordNotFound) } end end - describe '#in_era?' do - let!(:fee_era) { create(:fee_era)} - let!(:fee_era_with_no_start) { create(:fee_era_with_no_start)} - let!(:fee_era_with_no_end) { create(:fee_era_with_no_end)} + describe "#in_era?" do + let!(:fee_era) { create(:fee_era) } + let!(:fee_era_with_no_start) { create(:fee_era_with_no_start) } + let!(:fee_era_with_no_end) { create(:fee_era_with_no_end) } context "for current time" do - it { expect(fee_era.in_era?).to eq true } @@ -74,11 +73,10 @@ it { expect(fee_era_with_no_end.in_era?).to eq false } - end - context 'for passed time during current era' do - let(:time) { Time.new(2020, 5, 3)} + context "for passed time during current era" do + let(:time) { Time.new(2020, 5, 3) } it { expect(fee_era.in_era?(time)).to eq true } @@ -92,8 +90,8 @@ } end - context 'for passed time far in past' do - let(:time) { Time.new(2019, 5, 4)} + context "for passed time far in past" do + let(:time) { Time.new(2019, 5, 4) } it { expect(fee_era.in_era?(time)).to eq false } @@ -107,8 +105,8 @@ } end - context 'for passed time at the beginning of last era' do - let(:time) { Time.new(2020, 5, 7)} + context "for passed time at the beginning of last era" do + let(:time) { Time.new(2020, 5, 7) } it { expect(fee_era.in_era?(time)).to eq false } @@ -122,8 +120,8 @@ } end - context 'for passed time far in future' do - let(:time) { Time.new(2100, 5, 4)} + context "for passed time far in future" do + let(:time) { Time.new(2100, 5, 4) } it { expect(fee_era.in_era?(time)).to eq false } @@ -138,45 +136,44 @@ end end - context 'validation' do - it {is_expected.to validate_numericality_of(:international_surcharge_fee).is_greater_than_or_equal_to(0).is_less_than(1)} - it {is_expected.to have_many(:fee_structures).validate(true)} - it {is_expected.to have_one(:fee_coverage_detail_base).validate(true)} - it {is_expected.to validate_presence_of(:fee_coverage_detail_base)} + context "validation" do + it { is_expected.to validate_numericality_of(:international_surcharge_fee).is_greater_than_or_equal_to(0).is_less_than(1) } + it { is_expected.to have_many(:fee_structures).validate(true) } + it { is_expected.to have_one(:fee_coverage_detail_base).validate(true) } + it { is_expected.to validate_presence_of(:fee_coverage_detail_base) } end - describe '.find_fee_structure' do - context 'with structures for Visa, American Express and brandless' do - subject(:fee_era) { + describe ".find_fee_structure" do + context "with structures for Visa, American Express and brandless" do + subject(:fee_era) { create(:fee_era_with_structures) } - context 'for Visa' do - subject {fee_era.find_fee_structure_by_source(visa_card)} + context "for Visa" do + subject { fee_era.find_fee_structure_by_source(visa_card) } it { - is_expected.to have_attributes(brand: 'Visa') + is_expected.to have_attributes(brand: "Visa") } end - context 'for Amex' do - subject {fee_era.find_fee_structure_by_source(amex_card)} + context "for Amex" do + subject { fee_era.find_fee_structure_by_source(amex_card) } it { - is_expected.to have_attributes(brand: 'American Express') + is_expected.to have_attributes(brand: "American Express") } end - context 'and Discover' do - subject {fee_era.find_fee_structure_by_source(discover_card)} + context "and Discover" do + subject { fee_era.find_fee_structure_by_source(discover_card) } it { is_expected.to have_attributes(brand: nil) } end - context 'and invalid source' do + context "and invalid source" do it { - expect { fee_era.find_fee_structure_by_source(double("an invalid source"))}.to raise_error(ArgumentError) + expect { fee_era.find_fee_structure_by_source(double("an invalid source")) }.to raise_error(ArgumentError) } end end end - end diff --git a/spec/models/fee_structure_spec.rb b/spec/models/fee_structure_spec.rb index a818d86da..eaad8dd48 100644 --- a/spec/models/fee_structure_spec.rb +++ b/spec/models/fee_structure_spec.rb @@ -1,204 +1,212 @@ -require 'rails_helper' +require "rails_helper" -RSpec.shared_examples 'a fee structure with calculation arg validation' do - include_context 'Stripe::Source doubles' +RSpec.shared_examples "a fee structure with calculation arg validation" do + include_context "Stripe::Source doubles" let(:our_fee_structure) { subject } - - describe '#calculate_fee' do + + describe "#calculate_fee" do it { - expect { our_fee_structure.calculate_fee( - amount: -10, - source:source_from_us, - platform_fee: 0, - )}.to raise_error(ArgumentError) + expect { + our_fee_structure.calculate_fee( + amount: -10, + source: source_from_us, + platform_fee: 0 + ) + }.to raise_error(ArgumentError) } it { - expect { our_fee_structure.calculate_fee( - amount: 1000, - source: nil, - platform_fee: -1, - )}.to raise_error(ArgumentError) + expect { + our_fee_structure.calculate_fee( + amount: 1000, + source: nil, + platform_fee: -1 + ) + }.to raise_error(ArgumentError) } it { - expect { our_fee_structure.calculate_fee( - amount: 1000, - source:source_from_us, + expect { + our_fee_structure.calculate_fee( + amount: 1000, + source: source_from_us, platform_fee: 111, flat_fee: -1 - )}.to raise_error(ArgumentError) + ) + }.to raise_error(ArgumentError) } it { - expect { our_fee_structure.calculate_stripe_fee( - amount: 1000, + expect { + our_fee_structure.calculate_stripe_fee( + amount: 1000, source: double("an object without #brand or #country") - )}.to raise_error(ArgumentError) + ) + }.to raise_error(ArgumentError) } end - describe '#calculate_stripe_fee' do + describe "#calculate_stripe_fee" do it { - expect { our_fee_structure.calculate_stripe_fee( - amount: -10, - source:source_from_us, - )}.to raise_error(ArgumentError) + expect { + our_fee_structure.calculate_stripe_fee( + amount: -10, + source: source_from_us + ) + }.to raise_error(ArgumentError) } it { - expect { our_fee_structure.calculate_stripe_fee( - amount: 1000, - source:nil - )}.to raise_error(ArgumentError) + expect { + our_fee_structure.calculate_stripe_fee( + amount: 1000, + source: nil + ) + }.to raise_error(ArgumentError) } it { - expect { our_fee_structure.calculate_stripe_fee( - amount: 1000, + expect { + our_fee_structure.calculate_stripe_fee( + amount: 1000, source: double("an object without #brand or #country") - )}.to raise_error(ArgumentError) + ) + }.to raise_error(ArgumentError) } end end - - RSpec.describe FeeStructure, type: :model do - include_context 'Stripe::Source doubles' + include_context "Stripe::Source doubles" + context "validation" do + it { is_expected.to validate_presence_of(:stripe_fee) } + it { is_expected.to validate_numericality_of(:stripe_fee).is_greater_than_or_equal_to(0).is_less_than(1) } + it { is_expected.to validate_presence_of(:flat_fee) } + it { is_expected.to validate_numericality_of(:flat_fee).is_greater_than_or_equal_to(0).only_integer } - context 'validation' do - it {is_expected.to validate_presence_of(:stripe_fee)} - it {is_expected.to validate_numericality_of(:stripe_fee).is_greater_than_or_equal_to(0).is_less_than(1)} - it {is_expected.to validate_presence_of(:flat_fee)} - it {is_expected.to validate_numericality_of(:flat_fee).is_greater_than_or_equal_to(0).only_integer} - + it { is_expected.to validate_presence_of(:fee_era) } - it {is_expected.to validate_presence_of(:fee_era)} + it { is_expected.to delegate_method(:charge_international_fee?).to(:fee_era) } + it { is_expected.to delegate_method(:international_surcharge_fee).to(:fee_era) } - it {is_expected.to delegate_method(:charge_international_fee?).to(:fee_era)} - it {is_expected.to delegate_method(:international_surcharge_fee).to(:fee_era)} - - it {is_expected.to belong_to(:fee_era)} + it { is_expected.to belong_to(:fee_era) } end - describe '#calculate_fee' do - context 'using a fee structure with no local country' do - subject(:our_fee_structure) {create(:no_international_fees_brandless_fee_structure)} - it_behaves_like 'a fee structure with calculation arg validation' + describe "#calculate_fee" do + context "using a fee structure with no local country" do + subject(:our_fee_structure) { create(:no_international_fees_brandless_fee_structure) } + it_behaves_like "a fee structure with calculation arg validation" - context 'and with a US card' do + context "and with a US card" do it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee: "0.018", source: source_from_us)).to eq 430 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.018", source: source_from_us)).to eq 430 } it { - expect(our_fee_structure.calculate_fee(amount:100, platform_fee: "0.018", source: source_from_us)).to eq 34 + expect(our_fee_structure.calculate_fee(amount: 100, platform_fee: "0.018", source: source_from_us)).to eq 34 } it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee:"0.038", source: source_from_us)).to eq 630 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.038", source: source_from_us)).to eq 630 } end - - context 'and with a UK card' do + + context "and with a UK card" do it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee: "0.018", source: source_from_uk)).to eq 430 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.018", source: source_from_uk)).to eq 430 } it { - expect(our_fee_structure.calculate_fee(amount:100, platform_fee: "0.018", source: source_from_uk)).to eq 34 + expect(our_fee_structure.calculate_fee(amount: 100, platform_fee: "0.018", source: source_from_uk)).to eq 34 } it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee:"0.038", source: source_from_uk)).to eq 630 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.038", source: source_from_uk)).to eq 630 } end end - context 'using a fee structure with a local country of US' do - subject(:our_fee_structure) {create(:brandless_fee_structure)} - it_behaves_like 'a fee structure with calculation arg validation' - context 'and with a US card' do + context "using a fee structure with a local country of US" do + subject(:our_fee_structure) { create(:brandless_fee_structure) } + it_behaves_like "a fee structure with calculation arg validation" + context "and with a US card" do it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee: "0.018", source: source_from_us)).to eq 430 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.018", source: source_from_us)).to eq 430 } it { - expect(our_fee_structure.calculate_fee(amount:100, platform_fee: "0.018", source: source_from_us)).to eq 34 + expect(our_fee_structure.calculate_fee(amount: 100, platform_fee: "0.018", source: source_from_us)).to eq 34 } it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee:"0.038", source: source_from_us)).to eq 630 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.038", source: source_from_us)).to eq 630 } end - - context 'and with a UK card' do + + context "and with a UK card" do it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee: "0.018", source: source_from_uk)).to eq 530 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.018", source: source_from_uk)).to eq 530 } it { - expect(our_fee_structure.calculate_fee(amount:100, platform_fee: "0.018", source: source_from_uk)).to eq 35 + expect(our_fee_structure.calculate_fee(amount: 100, platform_fee: "0.018", source: source_from_uk)).to eq 35 } it { - expect(our_fee_structure.calculate_fee(amount:10000, platform_fee:"0.038", source: source_from_uk)).to eq 730 + expect(our_fee_structure.calculate_fee(amount: 10000, platform_fee: "0.038", source: source_from_uk)).to eq 730 } end end end + describe "#calculate_stripe_fee" do + context "using a fee structure with no local country" do + subject(:our_fee_structure) { create(:no_international_fees_brandless_fee_structure) } + it_behaves_like "a fee structure with calculation arg validation" - describe '#calculate_stripe_fee' do - context 'using a fee structure with no local country' do - subject(:our_fee_structure) {create(:no_international_fees_brandless_fee_structure)} - it_behaves_like 'a fee structure with calculation arg validation' - - context 'and with a US card' do + context "and with a US card" do it { - expect(our_fee_structure.calculate_stripe_fee(amount:10000, source: source_from_us)).to eq 250 + expect(our_fee_structure.calculate_stripe_fee(amount: 10000, source: source_from_us)).to eq 250 } it { - expect(our_fee_structure.calculate_stripe_fee(amount:100, source: source_from_us)).to eq 33 + expect(our_fee_structure.calculate_stripe_fee(amount: 100, source: source_from_us)).to eq 33 } - end - - context 'and with a UK card' do + + context "and with a UK card" do it { - expect(our_fee_structure.calculate_stripe_fee(amount:10000, source: source_from_uk)).to eq 250 + expect(our_fee_structure.calculate_stripe_fee(amount: 10000, source: source_from_uk)).to eq 250 } it { - expect(our_fee_structure.calculate_stripe_fee(amount:100, source: source_from_uk)).to eq 33 + expect(our_fee_structure.calculate_stripe_fee(amount: 100, source: source_from_uk)).to eq 33 } end end - context 'using a fee structure with a local country of US' do - subject(:our_fee_structure) {create(:brandless_fee_structure)} - it_behaves_like 'a fee structure with calculation arg validation' - - context 'and with a US card' do + context "using a fee structure with a local country of US" do + subject(:our_fee_structure) { create(:brandless_fee_structure) } + it_behaves_like "a fee structure with calculation arg validation" + + context "and with a US card" do it { - expect(our_fee_structure.calculate_stripe_fee(amount:10000, source: source_from_us)).to eq 250 + expect(our_fee_structure.calculate_stripe_fee(amount: 10000, source: source_from_us)).to eq 250 } it { - expect(our_fee_structure.calculate_stripe_fee(amount:100, source: source_from_us)).to eq 33 + expect(our_fee_structure.calculate_stripe_fee(amount: 100, source: source_from_us)).to eq 33 } end - - context 'and with a UK card' do + + context "and with a UK card" do it { - expect(our_fee_structure.calculate_stripe_fee(amount:10000, source: source_from_uk)).to eq 350 + expect(our_fee_structure.calculate_stripe_fee(amount: 10000, source: source_from_uk)).to eq 350 } it { - expect(our_fee_structure.calculate_stripe_fee(amount:100, source: source_from_uk)).to eq 34 + expect(our_fee_structure.calculate_stripe_fee(amount: 100, source: source_from_uk)).to eq 34 } end end diff --git a/spec/models/mailchimp_batch_operation_spec.rb b/spec/models/mailchimp_batch_operation_spec.rb index 25de91fa9..5250e1b0b 100644 --- a/spec/models/mailchimp_batch_operation_spec.rb +++ b/spec/models/mailchimp_batch_operation_spec.rb @@ -1,36 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe MailchimpBatchOperation, :type => :model do - - context 'when supporter.email is empty' do - describe '#to_h' do - it 'returns nil' do +RSpec.describe MailchimpBatchOperation, type: :model do + context "when supporter.email is empty" do + describe "#to_h" do + it "returns nil" do supporter = build_stubbed(:supporter_base) email_list = build_stubbed(:email_list_base) - operation = MailchimpBatchOperation.new(supporter: supporter, list: email_list, method: 'DELETE') + operation = MailchimpBatchOperation.new(supporter: supporter, list: email_list, method: "DELETE") expect(operation.to_h).to be_nil end end end - context 'when method == DELETE' do - describe '#to_h' do - it 'has no body key' do - supporter = build_stubbed(:supporter_base, email: 'something@email.com') + context "when method == DELETE" do + describe "#to_h" do + it "has no body key" do + supporter = build_stubbed(:supporter_base, email: "something@email.com") email_list = build_stubbed(:email_list_base) - operation = MailchimpBatchOperation.new(supporter: supporter, list: email_list, method: 'DELETE') + operation = MailchimpBatchOperation.new(supporter: supporter, list: email_list, method: "DELETE") - expect(operation.to_h).to eq({method: "DELETE", path: email_list.list_members_path + "/#{Digest::MD5.hexdigest(supporter.email.downcase).to_s}"}) + expect(operation.to_h).to eq({method: "DELETE", path: email_list.list_members_path + "/#{Digest::MD5.hexdigest(supporter.email.downcase)}"}) end end end - context 'when method == POST' do - describe '#to_h' do - it 'has a body key' do - supporter = build_stubbed(:supporter_base, email:"something@email.com") + context "when method == POST" do + describe "#to_h" do + it "has a body key" do + supporter = build_stubbed(:supporter_base, email: "something@email.com") email_list = build_stubbed(:email_list_base) - operation = MailchimpBatchOperation.new(supporter: supporter, list: email_list, method: 'POST') + operation = MailchimpBatchOperation.new(supporter: supporter, list: email_list, method: "POST") expect(operation.to_h).to match({method: "POST", path: email_list.list_members_path, body: an_instance_of(String)}) end diff --git a/spec/models/manual_balance_adjustment_spec.rb b/spec/models/manual_balance_adjustment_spec.rb index add384ced..e78569e1d 100644 --- a/spec/models/manual_balance_adjustment_spec.rb +++ b/spec/models/manual_balance_adjustment_spec.rb @@ -2,71 +2,68 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe ManualBalanceAdjustment, type: :model do - it {is_expected.to belong_to(:entity).required(true)} - it {is_expected.to belong_to(:payment).required(true)} - it {is_expected.to have_one(:supporter).through(:payment)} - it {is_expected.to have_one(:nonprofit).through(:payment)} - it {is_expected.to validate_presence_of(:gross_amount)} - it {is_expected.to validate_presence_of(:fee_total)} - it {is_expected.to validate_presence_of(:net_amount)} + it { is_expected.to belong_to(:entity).required(true) } + it { is_expected.to belong_to(:payment).required(true) } + it { is_expected.to have_one(:supporter).through(:payment) } + it { is_expected.to have_one(:nonprofit).through(:payment) } + it { is_expected.to validate_presence_of(:gross_amount) } + it { is_expected.to validate_presence_of(:fee_total) } + it { is_expected.to validate_presence_of(:net_amount) } - describe 'included in QueryPayments.ids_for_payout calculations' do - - it 'is not included when disbursed' do - Timecop.freeze(Time.new(2020,2, 1) - 1.day) do + describe "included in QueryPayments.ids_for_payout calculations" do + it "is not included when disbursed" do + Timecop.freeze(Time.new(2020, 2, 1) - 1.day) do manual_balance = create(:manual_balance_adjustment, :with_entity_and_payment, disbursed: true) - Timecop.freeze(Time.new(2020,2, 1)) do + Timecop.freeze(Time.new(2020, 2, 1)) do expect(QueryPayments.ids_for_payout(manual_balance.nonprofit.id)).to_not include manual_balance.payment.id end end end - it 'is included when not disbursed' do - Timecop.freeze(Time.new(2020,2, 1) - 1.day) do + it "is included when not disbursed" do + Timecop.freeze(Time.new(2020, 2, 1) - 1.day) do manual_balance = create(:manual_balance_adjustment, :with_entity_and_payment) - Timecop.freeze(Time.new(2020,2, 1)) do + Timecop.freeze(Time.new(2020, 2, 1)) do expect(QueryPayments.ids_for_payout(manual_balance.nonprofit.id)).to include manual_balance.payment.id end end end end - it 'included in QueryPayments.get_payout_totals calculations' do - Timecop.freeze(Time.new(2020,2, 1) - 1.day) do + it "included in QueryPayments.get_payout_totals calculations" do + Timecop.freeze(Time.new(2020, 2, 1) - 1.day) do manual_balance = create(:manual_balance_adjustment, :with_entity_and_payment) - Timecop.freeze(Time.new(2020,2, 1)) do - + Timecop.freeze(Time.new(2020, 2, 1)) do + expected_attributes = {"count" => 1, "gross_amount" => 0, "fee_total" => -100, "net_amount" => -100} - expected_attributes = {'count' => 1, 'gross_amount' => 0, 'fee_total' => -100, 'net_amount' => -100} - expect(QueryPayments.get_payout_totals(QueryPayments.ids_for_payout(manual_balance.nonprofit.id))).to eq expected_attributes end end end - describe 'included in QueryPayments.nonprofit_balances calculations' do - it 'is not included when disbursed' do - Timecop.freeze(Time.new(2020,2, 1) - 1.day) do + describe "included in QueryPayments.nonprofit_balances calculations" do + it "is not included when disbursed" do + Timecop.freeze(Time.new(2020, 2, 1) - 1.day) do manual_balance = create(:manual_balance_adjustment, :with_entity_and_payment, disbursed: true) - Timecop.freeze(Time.new(2020,2, 1)) do + Timecop.freeze(Time.new(2020, 2, 1)) do expect(QueryPayments.nonprofit_balances(manual_balance.nonprofit.id)).to eq({ - 'available' => {'gross' =>0, 'net' => 0}, - 'pending' => {'gross' => 0, 'net' => 0} + "available" => {"gross" => 0, "net" => 0}, + "pending" => {"gross" => 0, "net" => 0} }) end end end - it 'is included when not disbursed' do - Timecop.freeze(Time.new(2020,2, 1) - 1.day) do + it "is included when not disbursed" do + Timecop.freeze(Time.new(2020, 2, 1) - 1.day) do manual_balance = create(:manual_balance_adjustment, :with_entity_and_payment) - Timecop.freeze(Time.new(2020,2, 1)) do + Timecop.freeze(Time.new(2020, 2, 1)) do expect(QueryPayments.nonprofit_balances(manual_balance.nonprofit.id)).to eq({ - 'available' => {'gross'=> 0, 'net' => -100}, - 'pending' => {'gross' => 0, 'net' => 0} + "available" => {"gross" => 0, "net" => -100}, + "pending" => {"gross" => 0, "net" => 0} }) end end diff --git a/spec/models/misc_campaign_info_spec.rb b/spec/models/misc_campaign_info_spec.rb index 62cd7bc30..175d5b513 100644 --- a/spec/models/misc_campaign_info_spec.rb +++ b/spec/models/misc_campaign_info_spec.rb @@ -1,8 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe MiscCampaignInfo, :type => :model do - it {is_expected.to have_db_column(:fee_coverage_option_config).of_type(:string).with_options(null: true, default: nil) } +RSpec.describe MiscCampaignInfo, type: :model do + it { is_expected.to have_db_column(:fee_coverage_option_config).of_type(:string).with_options(null: true, default: nil) } - it {is_expected.to validate_inclusion_of(:fee_coverage_option_config).in_array(['auto', 'manual', 'none', nil])} + it { is_expected.to validate_inclusion_of(:fee_coverage_option_config).in_array(["auto", "manual", "none", nil]) } end diff --git a/spec/models/misc_refund_info_spec.rb b/spec/models/misc_refund_info_spec.rb index 3bc77196b..433cea39c 100644 --- a/spec/models/misc_refund_info_spec.rb +++ b/spec/models/misc_refund_info_spec.rb @@ -1,5 +1,5 @@ -require 'rails_helper' +require "rails_helper" -RSpec.describe MiscRefundInfo, :type => :model do +RSpec.describe MiscRefundInfo, type: :model do pending "add some examples to (or delete) #{__FILE__}" end diff --git a/spec/models/miscellaneous_np_info_spec.rb b/spec/models/miscellaneous_np_info_spec.rb index a74b7d480..a57c43867 100644 --- a/spec/models/miscellaneous_np_info_spec.rb +++ b/spec/models/miscellaneous_np_info_spec.rb @@ -1,8 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe MiscellaneousNpInfo, :type => :model do - it {is_expected.to have_db_column(:fee_coverage_option_config).of_type(:string).with_options(null: true, default: nil) } +RSpec.describe MiscellaneousNpInfo, type: :model do + it { is_expected.to have_db_column(:fee_coverage_option_config).of_type(:string).with_options(null: true, default: nil) } - it {is_expected.to validate_inclusion_of(:fee_coverage_option_config).in_array(['auto', 'manual', 'none', nil])} + it { is_expected.to validate_inclusion_of(:fee_coverage_option_config).in_array(["auto", "manual", "none", nil]) } end diff --git a/spec/models/modern_donation_spec.rb b/spec/models/modern_donation_spec.rb index a1aba3939..54efdc9e1 100644 --- a/spec/models/modern_donation_spec.rb +++ b/spec/models/modern_donation_spec.rb @@ -1,9 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe ModernDonation, type: :model do - it_behaves_like 'trx assignable', :don - it_behaves_like 'an object with as_money attributes', :amount + it_behaves_like "trx assignable", :don + it_behaves_like "an object with as_money attributes", :amount it { is_expected.to delegate_method(:designation).to(:legacy_donation) @@ -15,28 +15,27 @@ it { is_expected.to(belong_to(:legacy_donation) - .class_name('Donation') - .with_foreign_key('donation_id') - ) + .class_name("Donation") + .with_foreign_key("donation_id")) } - describe '#dedication' do - context 'when legacy_donation has no dedication' do + describe "#dedication" do + context "when legacy_donation has no dedication" do it { - expect(ModernDonation.new(legacy_donation:Donation.new).dedication).to be_nil + expect(ModernDonation.new(legacy_donation: Donation.new).dedication).to be_nil } end - context 'when legacy_donation has non-json parsable dedication' do + context "when legacy_donation has non-json parsable dedication" do it { - expect(ModernDonation.new(legacy_donation:Donation.new(dedication: "Somest string")).dedication).to be_nil + expect(ModernDonation.new(legacy_donation: Donation.new(dedication: "Somest string")).dedication).to be_nil } end - context 'when legacy_donation has json parsable dedication' do + context "when legacy_donation has json parsable dedication" do it { input_json = {note: "My mom", type: "honor"} - expect(ModernDonation.new(legacy_donation:Donation.new(dedication: input_json.to_json)).dedication).to include_json **input_json + expect(ModernDonation.new(legacy_donation: Donation.new(dedication: input_json.to_json)).dedication).to include_json(**input_json) } end end diff --git a/spec/models/nonprofit_deactivations_spec.rb b/spec/models/nonprofit_deactivations_spec.rb index 0ed51eac1..6841ccd3b 100644 --- a/spec/models/nonprofit_deactivations_spec.rb +++ b/spec/models/nonprofit_deactivations_spec.rb @@ -1,30 +1,26 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe NonprofitDeactivation, type: :model do - def create_activated_and_unactivated_nps OpenStruct.new activated: [ create(:nonprofit_base), create(:nonprofit_base, :activated_deactivation_record) - ], - deactivated: [ - create(:nonprofit_base, :deactivate_nonprofit) - ] + ], + deactivated: [ + create(:nonprofit_base, :deactivate_nonprofit) + ] end - describe '.activated' do - it 'has all of the nps in activated except last one' do + describe ".activated" do + it "has all of the nps in activated except last one" do nps = create_activated_and_unactivated_nps - + expect(Nonprofit.activated.all).to match_array(nps.activated) end end - - - it 'has only nps in deactivated' do - + it "has only nps in deactivated" do nps = create_activated_and_unactivated_nps expect(Nonprofit.deactivated.all).to match_array(nps.deactivated) end diff --git a/spec/models/nonprofit_key_spec.rb b/spec/models/nonprofit_key_spec.rb index 90b9f5319..68c5d731c 100644 --- a/spec/models/nonprofit_key_spec.rb +++ b/spec/models/nonprofit_key_spec.rb @@ -1,15 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe NonprofitKey, type: :model do - - around(:each) {|example| - - current_cypher_key = ENV['CYPHER_KEY'] - ENV['CYPHER_KEY'] = "xGhMrqIixKvQ4S1bqv8CYwxGhMrqIixKvQ4S1bqv8CY=\n" # test cypher key; don't use anywhere for real code + around(:each) { |example| + current_cypher_key = ENV["CYPHER_KEY"] + ENV["CYPHER_KEY"] = "xGhMrqIixKvQ4S1bqv8CYwxGhMrqIixKvQ4S1bqv8CY=\n" # test cypher key; don't use anywhere for real code example.run - ENV['CYPHER_KEY'] = current_cypher_key - + ENV["CYPHER_KEY"] = current_cypher_key } it { @@ -20,25 +17,22 @@ is_expected.to validate_presence_of(:mailchimp_token) } - - describe '#mailchimp_token' do + describe "#mailchimp_token" do it { expect(create(:nonprofit_key).mailchimp_token).to eq "a token" } - - - it 'roundtrips mailchimp_token properly' do + it "roundtrips mailchimp_token properly" do key = create(:nonprofit_key) key.mailchimp_token = "a different token" key.save! - + new_key_object = NonprofitKey.find(key.id) expect(new_key_object.mailchimp_token).to eq "a different token" end - it 'handles nil values properly' do + it "handles nil values properly" do key = create(:nonprofit_key) expect { key.mailchimp_token = nil @@ -46,5 +40,4 @@ expect(key.mailchimp_token).to be_nil end end - end diff --git a/spec/models/nonprofit_s3_key_spec.rb b/spec/models/nonprofit_s3_key_spec.rb index 9b5179dd0..d5cade6ff 100644 --- a/spec/models/nonprofit_s3_key_spec.rb +++ b/spec/models/nonprofit_s3_key_spec.rb @@ -1,10 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe NonprofitS3Key, type: :model do - it { is_expected.to belong_to(:nonprofit).required} + it { is_expected.to belong_to(:nonprofit).required } - it { is_expected.to validate_presence_of(:access_key_id)} - it { is_expected.to validate_presence_of(:secret_access_key)} - it { is_expected.to validate_presence_of(:bucket_name)} + it { is_expected.to validate_presence_of(:access_key_id) } + it { is_expected.to validate_presence_of(:secret_access_key) } + it { is_expected.to validate_presence_of(:bucket_name) } end diff --git a/spec/models/nonprofit_spec.rb b/spec/models/nonprofit_spec.rb index 80396e72c..d94a8319f 100644 --- a/spec/models/nonprofit_spec.rb +++ b/spec/models/nonprofit_spec.rb @@ -1,64 +1,63 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe Nonprofit, type: :model do - it_behaves_like 'an houidable entity', :np + it_behaves_like "an houidable entity", :np - it {is_expected.to validate_presence_of(:name)} - - it {is_expected.to validate_presence_of(:city)} - it {is_expected.to validate_presence_of(:state_code)} + it { is_expected.to validate_presence_of(:name) } - it {is_expected.to validate_presence_of(:slug)} - - it {expect(create(:nonprofit)).to validate_uniqueness_of(:slug).scoped_to(:city_slug, :state_code_slug)} + it { is_expected.to validate_presence_of(:city) } + it { is_expected.to validate_presence_of(:state_code) } - it{ is_expected.to have_one(:billing_plan).through(:billing_subscription)} + it { is_expected.to validate_presence_of(:slug) } - it {is_expected.to have_many(:supporter_cards).class_name('Card').through(:supporters).source(:cards)} + it { expect(create(:nonprofit)).to validate_uniqueness_of(:slug).scoped_to(:city_slug, :state_code_slug) } - it {is_expected.to have_many(:disputes).through(:charges)} + it { is_expected.to have_one(:billing_plan).through(:billing_subscription) } - it {is_expected.to have_many(:email_lists)} - it {is_expected.to have_one(:nonprofit_key)} + it { is_expected.to have_many(:supporter_cards).class_name("Card").through(:supporters).source(:cards) } - it {is_expected.to have_many(:email_customizations)} + it { is_expected.to have_many(:disputes).through(:charges) } - it {is_expected.to have_many(:associated_object_events).class_name("ObjectEvent")} + it { is_expected.to have_many(:email_lists) } + it { is_expected.to have_one(:nonprofit_key) } - describe 'with cards' do + it { is_expected.to have_many(:email_customizations) } + + it { is_expected.to have_many(:associated_object_events).class_name("ObjectEvent") } + + describe "with cards" do around(:each) do |ex| StripeMockHelper.start ex.run StripeMockHelper.stop end - + before(:each) do @nonprofit = create(:nonprofit_with_cards) - end - before (:each) do + before(:each) do cards = @nonprofit.cards.to_ary - @card1 = cards.first{|i| i.name == 'card1'} - @card2 = cards.first{|i| i.name == 'card2'} - @card3 = cards.first{|i| i.name == 'card3'} + @card1 = cards.first { |i| i.name == "card1" } + @card2 = cards.first { |i| i.name == "card2" } + @card3 = cards.first { |i| i.name == "card3" } end - describe '.active_cards' do - it 'should return all cards' do + describe ".active_cards" do + it "should return all cards" do cards = @nonprofit.active_cards expect(cards.length).to eq(2) end end - describe '.active_card' do - it 'should return one' do + describe ".active_card" do + it "should return one" do card = @nonprofit.active_card expect(card).to_not be_nil end end - describe '.create_active_card' do - it 'should become active and turn others inactive' do - previously_active_cards = @nonprofit.active_cards - card = @nonprofit.create_active_card(name: 'card 4') + describe ".create_active_card" do + it "should become active and turn others inactive" do + @nonprofit.active_cards + card = @nonprofit.create_active_card(name: "card 4") expect(card).to_not be_nil expect(card.name).to eq(@nonprofit.active_card.name) expect(!card.inactive) @@ -66,94 +65,92 @@ end end - describe '#fee_coverage_option' do - let(:nonprofit) {build(:nonprofit)} + describe "#fee_coverage_option" do + let(:nonprofit) { build(:nonprofit) } - it 'is set to auto when miscellaneous_np_info is missing' do - expect(nonprofit.fee_coverage_option).to eq 'auto' + it "is set to auto when miscellaneous_np_info is missing" do + expect(nonprofit.fee_coverage_option).to eq "auto" end - it 'is set to auto when miscellaneous_np_info.fee_coverage_option_config is nil' do + it "is set to auto when miscellaneous_np_info.fee_coverage_option_config is nil" do nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: nil) - expect(nonprofit.fee_coverage_option).to eq 'auto' + expect(nonprofit.fee_coverage_option).to eq "auto" end - it 'is set to manual when miscellaneous_np_info.fee_coverage_option_config is manual' do - nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: 'manual') - expect(nonprofit.fee_coverage_option).to eq 'manual' + it "is set to manual when miscellaneous_np_info.fee_coverage_option_config is manual" do + nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: "manual") + expect(nonprofit.fee_coverage_option).to eq "manual" end - it 'is set to auto when miscellaneous_np_info.fee_coverage_option_config is auto' do - nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: 'auto') - expect(nonprofit.fee_coverage_option).to eq 'auto' + it "is set to auto when miscellaneous_np_info.fee_coverage_option_config is auto" do + nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: "auto") + expect(nonprofit.fee_coverage_option).to eq "auto" end - it 'is set to none when miscellaneous_np_info.fee_coverage_option_config is none' do - nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: 'none') - expect(nonprofit.fee_coverage_option).to eq 'none' + it "is set to none when miscellaneous_np_info.fee_coverage_option_config is none" do + nonprofit.miscellaneous_np_info = build(:miscellaneous_np_info, fee_coverage_option_config: "none") + expect(nonprofit.fee_coverage_option).to eq "none" end end - describe '.currency_symbol' do - - let(:nonprofit) {force_create(:nonprofit, currency: 'eur')} - let(:euro){"€"} + describe ".currency_symbol" do + let(:nonprofit) { force_create(:nonprofit, currency: "eur") } + let(:euro) { "€" } - it 'finds correct currency symbol for nonprofit' do + it "finds correct currency symbol for nonprofit" do expect(nonprofit.currency_symbol).to eq euro end end - describe '.can_make_payouts?' do - let(:np) {force_create(:nonprofit, stripe_account_id: '1')} - let(:np_vetted) {force_create(:nonprofit, vetted:true, stripe_account_id: '1')} - let(:bank_account) {force_create(:bank_account, nonprofit: np_vetted)} - let(:bank_account_deleted) {force_create(:bank_account, deleted: true)} - let(:bank_account_pending) {force_create(:bank_account, pending_verification:true)} - - let(:stripe_account) { force_create(:stripe_account, stripe_account_id: '1')} - let(:stripe_account_payouts_enabled) { force_create(:stripe_account, stripe_account_id: '1', payouts_enabled: true)} + describe ".can_make_payouts?" do + let(:np) { force_create(:nonprofit, stripe_account_id: "1") } + let(:np_vetted) { force_create(:nonprofit, vetted: true, stripe_account_id: "1") } + let(:bank_account) { force_create(:bank_account, nonprofit: np_vetted) } + let(:bank_account_deleted) { force_create(:bank_account, deleted: true) } + let(:bank_account_pending) { force_create(:bank_account, pending_verification: true) } - let(:nonprofit_deactivation) {force_create(:nonprofit_deactivation, nonprofit: np_vetted)} - let(:nonprofit_deactivation_deactivated) {force_create(:nonprofit_deactivation, deactivated: true, nonprofit: np_vetted)} + let(:stripe_account) { force_create(:stripe_account, stripe_account_id: "1") } + let(:stripe_account_payouts_enabled) { force_create(:stripe_account, stripe_account_id: "1", payouts_enabled: true) } + let(:nonprofit_deactivation) { force_create(:nonprofit_deactivation, nonprofit: np_vetted) } + let(:nonprofit_deactivation_deactivated) { force_create(:nonprofit_deactivation, deactivated: true, nonprofit: np_vetted) } - it 'is false on unvetted' do + it "is false on unvetted" do np expect(np.can_make_payouts?).to be false end - it 'is false on no bank account' do + it "is false on no bank account" do np_vetted expect(np_vetted.can_make_payouts?).to be false end - it 'is false on deleted bank account' do + it "is false on deleted bank account" do np_vetted bank_account_deleted expect(np_vetted.can_make_payouts?).to be false end - it 'is false on pending bank account' do + it "is false on pending bank account" do np_vetted bank_account_pending expect(np_vetted.can_make_payouts?).to be false end - it 'is false on no stripe_account' do + it "is false on no stripe_account" do np_vetted bank_account expect(np_vetted.can_make_payouts?).to be false end - it 'is false on stripe_account without payouts_enabled' do + it "is false on stripe_account without payouts_enabled" do np_vetted bank_account stripe_account expect(np_vetted.can_make_payouts?).to be false end - it 'is false on deactivated nonprofit' do + it "is false on deactivated nonprofit" do np_vetted bank_account stripe_account_payouts_enabled @@ -161,14 +158,14 @@ expect(np_vetted.can_make_payouts?).to be false end - it 'is true when no nonprofit_deactivaton record exists' do + it "is true when no nonprofit_deactivaton record exists" do np_vetted bank_account stripe_account_payouts_enabled expect(np_vetted.can_make_payouts?).to be true end - it 'is true when nonprofit_deactivaton record exists but not deactivated' do + it "is true when nonprofit_deactivaton record exists but not deactivated" do np_vetted bank_account stripe_account_payouts_enabled @@ -177,184 +174,176 @@ end end - describe '.can_process_charge?' do - let(:nonprofit_vetted) { build(:nonprofit, vetted: true)} - let(:nonprofit_unvetted) { build(:nonprofit, vetted: false)} - let(:nonprofit_deactivation_true) { build(:nonprofit_deactivation, deactivated: true)} - let(:nonprofit_deactivation_false) { build(:nonprofit_deactivation, deactivated: false)} + describe ".can_process_charge?" do + let(:nonprofit_vetted) { build(:nonprofit, vetted: true) } + let(:nonprofit_unvetted) { build(:nonprofit, vetted: false) } + let(:nonprofit_deactivation_true) { build(:nonprofit_deactivation, deactivated: true) } + let(:nonprofit_deactivation_false) { build(:nonprofit_deactivation, deactivated: false) } - let(:stripe_account_enabled) { build(:stripe_account, charges_enabled:true)} - let(:stripe_account_disabled) { build(:stripe_account, charges_enabled:false)} + let(:stripe_account_enabled) { build(:stripe_account, charges_enabled: true) } + let(:stripe_account_disabled) { build(:stripe_account, charges_enabled: false) } - it 'fails when unvetted, deactivated nil, stripe disabled' do + it "fails when unvetted, deactivated nil, stripe disabled" do nonprofit_unvetted.stripe_account = stripe_account_disabled expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated nil, stripe nil' do + it "fails when unvetted, deactivated nil, stripe nil" do expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated false, stripe disabled' do + it "fails when unvetted, deactivated false, stripe disabled" do nonprofit_unvetted.stripe_account = stripe_account_disabled nonprofit_unvetted.nonprofit_deactivation = nonprofit_deactivation_false expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated false, stripe nil' do + it "fails when unvetted, deactivated false, stripe nil" do nonprofit_unvetted.nonprofit_deactivation = nonprofit_deactivation_false expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated true, stripe disabled' do + it "fails when unvetted, deactivated true, stripe disabled" do nonprofit_unvetted.stripe_account = stripe_account_disabled nonprofit_unvetted.nonprofit_deactivation = nonprofit_deactivation_true expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated true, stripe nil' do + it "fails when unvetted, deactivated true, stripe nil" do nonprofit_unvetted.nonprofit_deactivation = nonprofit_deactivation_true expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated true, stripe enabled' do + it "fails when unvetted, deactivated true, stripe enabled" do nonprofit_unvetted.stripe_account = stripe_account_enabled nonprofit_unvetted.nonprofit_deactivation = nonprofit_deactivation_true expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated false, stripe enabled' do + it "fails when unvetted, deactivated false, stripe enabled" do nonprofit_unvetted.stripe_account = stripe_account_enabled nonprofit_unvetted.nonprofit_deactivation = nonprofit_deactivation_false expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when unvetted, deactivated nil, stripe enabled' do + it "fails when unvetted, deactivated nil, stripe enabled" do nonprofit_unvetted.stripe_account = stripe_account_enabled expect(nonprofit_unvetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated nil, stripe disabled' do + it "fails when vetted, deactivated nil, stripe disabled" do nonprofit_vetted.stripe_account = stripe_account_disabled expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated nil, stripe nil' do + it "fails when vetted, deactivated nil, stripe nil" do expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated false, stripe disabled' do + it "fails when vetted, deactivated false, stripe disabled" do nonprofit_vetted.stripe_account = stripe_account_disabled nonprofit_vetted.nonprofit_deactivation = nonprofit_deactivation_false expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated false, stripe nil' do + it "fails when vetted, deactivated false, stripe nil" do nonprofit_vetted.nonprofit_deactivation = nonprofit_deactivation_false expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated true, stripe disabled' do + it "fails when vetted, deactivated true, stripe disabled" do nonprofit_vetted.stripe_account = stripe_account_disabled nonprofit_vetted.nonprofit_deactivation = nonprofit_deactivation_true expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated true, stripe nil' do + it "fails when vetted, deactivated true, stripe nil" do nonprofit_vetted.nonprofit_deactivation = nonprofit_deactivation_true expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'fails when vetted, deactivated true, stripe enabled' do + it "fails when vetted, deactivated true, stripe enabled" do nonprofit_vetted.stripe_account = stripe_account_enabled nonprofit_vetted.nonprofit_deactivation = nonprofit_deactivation_true expect(nonprofit_vetted.can_process_charge?).to eq false end - it 'succeed when vetted, deactivated false, stripe enabled' do + it "succeed when vetted, deactivated false, stripe enabled" do nonprofit_vetted.stripe_account = stripe_account_enabled nonprofit_vetted.nonprofit_deactivation = nonprofit_deactivation_false expect(nonprofit_vetted.can_process_charge?).to eq true end - it 'succeeds when vetted, deactivated nil and stripe enabled' do + it "succeeds when vetted, deactivated nil and stripe enabled" do nonprofit_vetted.stripe_account = stripe_account_enabled expect(nonprofit_vetted.can_process_charge?).to eq true end end - describe '.timezone_is_valid' do - it 'does not fail if the timezone is nil' do + describe ".timezone_is_valid" do + it "does not fail if the timezone is nil" do expect { create(:nonprofit, timezone: nil) }.not_to raise_error end - it 'does not fail if the timezone is readable by postgres' do - expect { create(:nonprofit, timezone: 'America/Chicago') }.not_to raise_error + it "does not fail if the timezone is readable by postgres" do + expect { create(:nonprofit, timezone: "America/Chicago") }.not_to raise_error end - it 'raises error if the timezone is invalid' do - expect { create(:nonprofit, timezone: 'Central Time (US & Canada)') }.to raise_error(ActiveRecord::RecordInvalid) + it "raises error if the timezone is invalid" do + expect { create(:nonprofit, timezone: "Central Time (US & Canada)") }.to raise_error(ActiveRecord::RecordInvalid) end end - it '#url returns slugged_nonprofit_path' do + it "#url returns slugged_nonprofit_path" do nonprofit = create(:nonprofit_base) expect(nonprofit.url).to eq "/#{nonprofit.state_code_slug}/#{nonprofit.city_slug}/#{nonprofit.slug}" end - describe '::FeeCalculation' do - include_context 'common fee scenarios' - subject(:nonprofit){ create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)} + describe "::FeeCalculation" do + include_context "common fee scenarios" + subject(:nonprofit) { create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat) } SCENARIOS.each do |example| - - describe '#calculate_fee' do - context "when charge is #{example[:at]}" do + describe "#calculate_fee" do + context "when charge is #{example[:at]}" do context "for #{example[:source]}" do - it { - expect(nonprofit.calculate_fee(amount:example[:amount], source: get_source(example), at: at(example))).to eq example[:calculate_fee_result] - } + it { + expect(nonprofit.calculate_fee(amount: example[:amount], source: get_source(example), at: at(example))).to eq example[:calculate_fee_result] + } end end end - describe '#calculate_stripe_fee' do - - let(:calculate_stripe_fee_result) { + describe "#calculate_stripe_fee" do + let(:calculate_stripe_fee_result) { example[:calculate_stripe_fee_result] } - context "when charge is #{example[:at]}" do + context "when charge is #{example[:at]}" do context "for #{example[:source]}" do - - it { - expect(nonprofit.calculate_stripe_fee(amount:example[:amount], source: get_source(example), at: at(example))).to eq calculate_stripe_fee_result + expect(nonprofit.calculate_stripe_fee(amount: example[:amount], source: get_source(example), at: at(example))).to eq calculate_stripe_fee_result } end end end - describe '#calculate_application_fee_refund' do - + describe "#calculate_application_fee_refund" do context "when charge is #{example[:at]}" do context "for #{example[:source]}" do example[:refunds].each do |refund| context "with following inputs #{refund}" do - - let(:stripe_charge) { - Stripe::Charge.construct_from({id: 'charge_id_1', amount: example[:amount], source: get_source(example), application_fee: 'app_fee_1', created: (Time.current).to_i, refunded: refund[:charge_marked_as_refunded]}) - + let(:stripe_charge) { + Stripe::Charge.construct_from({id: "charge_id_1", amount: example[:amount], source: get_source(example), application_fee: "app_fee_1", created: Time.current.to_i, refunded: refund[:charge_marked_as_refunded]}) } - let(:stripe_refund) { + let(:stripe_refund) { Stripe::Refund.construct_from({charge: stripe_charge.id, amount: refund[:amount_refunded]}) } let(:stripe_application_fee) { - Stripe::ApplicationFee.construct_from({amount_refunded: refund[:application_fee_refunded_already], id: 'app_fee_1', amount: example[:calculate_fee_result]}) + Stripe::ApplicationFee.construct_from({amount_refunded: refund[:application_fee_refunded_already], id: "app_fee_1", amount: example[:calculate_fee_result]}) } - - + it { expect(nonprofit.calculate_application_fee_refund(charge_date: at(example), charge: stripe_charge, refund: stripe_refund, application_fee: stripe_application_fee)).to eq refund[:calculate_application_fee_refund_result] } @@ -365,16 +354,16 @@ end end - describe '#fee_coverage_details' do - context 'for a nonprofit with CC percentage_fee 2.5% + 5 cents' do - let(:nonprofit){ create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)} + describe "#fee_coverage_details" do + context "for a nonprofit with CC percentage_fee 2.5% + 5 cents" do + let(:nonprofit) { create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat) } it { expect(nonprofit.fee_coverage_details).to eq({percentage_fee: BigDecimal("0.025") + BigDecimal("0.022"), flat_fee: 35}) } end - context 'for a nonprofit with CC percentage_fee 2.5% + 5 cents but in a fee era where we dont consider billing plan' do - let(:nonprofit){ create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)} - before(:each) do + context "for a nonprofit with CC percentage_fee 2.5% + 5 cents but in a fee era where we dont consider billing plan" do + let(:nonprofit) { create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat) } + before(:each) do FeeEra.current.fee_coverage_detail_base = build(:dont_consider_billing_plan_fee_coverage_detail_base) FeeEra.current.fee_coverage_detail_base.save! end @@ -383,8 +372,8 @@ expect(nonprofit.fee_coverage_details).to eq({percentage_fee: BigDecimal("0.05"), flat_fee: 0}) } end - context 'for a nonprofit without a stripe account set up (billing_plan is missing)' do - let(:nonprofit){ create(:nonprofit, billing_plan: nil) } + context "for a nonprofit without a stripe account set up (billing_plan is missing)" do + let(:nonprofit) { create(:nonprofit, billing_plan: nil) } it { expect(nonprofit.fee_coverage_details).to eq( @@ -394,44 +383,43 @@ } ) } - end end - describe '#fee_coverage_details_with_json_safe_keys' do - context 'for a nonprofit with CC percentage_fee 2.5% + 5 cents' do - let(:nonprofit){ create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)} + describe "#fee_coverage_details_with_json_safe_keys" do + context "for a nonprofit with CC percentage_fee 2.5% + 5 cents" do + let(:nonprofit) { create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat) } it { - expect(nonprofit.fee_coverage_details_with_json_safe_keys).to eq({'percentageFee' => BigDecimal("0.025") + BigDecimal("0.022"), 'flatFee' => 35}) + expect(nonprofit.fee_coverage_details_with_json_safe_keys).to eq({"percentageFee" => BigDecimal("0.025") + BigDecimal("0.022"), "flatFee" => 35}) } end - context 'for a nonprofit with CC percentage_fee 2.5% + 5 cents but in a fee era where we dont consider billing plan' do - let(:nonprofit){ create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat)} - before(:each) do + context "for a nonprofit with CC percentage_fee 2.5% + 5 cents but in a fee era where we dont consider billing plan" do + let(:nonprofit) { create(:nonprofit_with_billing_plan_percentage_fee_of_2_5_percent_and_5_cents_flat) } + before(:each) do FeeEra.current.fee_coverage_detail_base = build(:dont_consider_billing_plan_fee_coverage_detail_base) FeeEra.current.fee_coverage_detail_base.save! end it { - expect(nonprofit.fee_coverage_details_with_json_safe_keys).to eq({'percentageFee' => BigDecimal("0.05"), 'flatFee' => 0}) + expect(nonprofit.fee_coverage_details_with_json_safe_keys).to eq({"percentageFee" => BigDecimal("0.05"), "flatFee" => 0}) } end end end - describe '::Deactivation' do - let(:nonprofit_without_deactivation_record) { create(:nonprofit)} + describe "::Deactivation" do + let(:nonprofit_without_deactivation_record) { create(:nonprofit) } - let(:nonprofit_with_deactivated_deactivation_record) { - create(:nonprofit_with_deactivated_deactivation_record) + let(:nonprofit_with_deactivated_deactivation_record) { + create(:nonprofit_with_deactivated_deactivation_record) } - let(:nonprofit_with_activated_deactivation_record) { + let(:nonprofit_with_activated_deactivation_record) { create(:nonprofit_with_activated_deactivation_record) } - describe '.activated' do + describe ".activated" do it { nonprofit_without_deactivation_record expect(Nonprofit.activated).to include nonprofit_without_deactivation_record @@ -448,7 +436,7 @@ } end - describe '.deactivated' do + describe ".deactivated" do it { nonprofit_without_deactivation_record expect(Nonprofit.deactivated).to_not include nonprofit_without_deactivation_record @@ -465,8 +453,7 @@ } end - describe '#activated?' do - + describe "#activated?" do it { expect(nonprofit_without_deactivation_record.activated?).to eq true } @@ -480,7 +467,7 @@ } end - describe '#deactivated?' do + describe "#deactivated?" do it { expect(nonprofit_without_deactivation_record.deactivated?).to eq false } @@ -494,7 +481,7 @@ } end - describe '#deactivate!' do + describe "#deactivate!" do it { nonprofit_without_deactivation_record.deactivate! expect(nonprofit_without_deactivation_record.published).to eq false @@ -515,92 +502,90 @@ end end - describe '::S3Keys' do - it {is_expected.to have_many(:nonprofit_s3_keys)} + describe "::S3Keys" do + it { is_expected.to have_many(:nonprofit_s3_keys) } end - describe '::DateAndTime' do - - describe '#zone' do - it 'returns UTC if the nonprofit has no timezone' do - expect(build(:nonprofit).zone).to eq ActiveSupport::TimeZone['UTC'] + describe "::DateAndTime" do + describe "#zone" do + it "returns UTC if the nonprofit has no timezone" do + expect(build(:nonprofit).zone).to eq ActiveSupport::TimeZone["UTC"] end - - it 'returns UTC if the nonprofit has a blank timezone' do - expect(build(:nonprofit, timezone: '').zone).to eq ActiveSupport::TimeZone['UTC'] + + it "returns UTC if the nonprofit has a blank timezone" do + expect(build(:nonprofit, timezone: "").zone).to eq ActiveSupport::TimeZone["UTC"] end - it 'returns UTC if the nonprofit has an invalid timezone' do - expect(build(:nonprofit, timezone: 'invalid time').zone).to eq ActiveSupport::TimeZone['UTC'] + it "returns UTC if the nonprofit has an invalid timezone" do + expect(build(:nonprofit, timezone: "invalid time").zone).to eq ActiveSupport::TimeZone["UTC"] end - it 'returns non-UTC timezone if the nonprofit has an valid timezone' do - expect(build(:nonprofit, timezone: 'Central Time (US & Canada)').zone).to eq ActiveSupport::TimeZone['Central Time (US & Canada)'] + it "returns non-UTC timezone if the nonprofit has an valid timezone" do + expect(build(:nonprofit, timezone: "Central Time (US & Canada)").zone).to eq ActiveSupport::TimeZone["Central Time (US & Canada)"] end end - describe '#use_zone' do - it 'makes times in UTC if no zone provided' do + describe "#use_zone" do + it "makes times in UTC if no zone provided" do np = build(:nonprofit) beginning_of_year_in_np_zone = nil np.use_zone do beginning_of_year_in_np_zone = Time.current.beginning_of_year end - expect(beginning_of_year_in_np_zone).to eq ActiveSupport::TimeZone['UTC'].now.beginning_of_year + expect(beginning_of_year_in_np_zone).to eq ActiveSupport::TimeZone["UTC"].now.beginning_of_year end - it 'makes times in local zones if zone provided' do - np = build(:nonprofit, timezone: 'Central Time (US & Canada)') + it "makes times in local zones if zone provided" do + np = build(:nonprofit, timezone: "Central Time (US & Canada)") beginning_of_year_in_np_zone = nil np.use_zone do beginning_of_year_in_np_zone = Time.current.beginning_of_year end # do they represent the same time? - expect(beginning_of_year_in_np_zone.to_i).to eq (ActiveSupport::TimeZone['UTC'].now.beginning_of_year + 6.hours).to_i + expect(beginning_of_year_in_np_zone.to_i).to eq (ActiveSupport::TimeZone["UTC"].now.beginning_of_year + 6.hours).to_i end end end - describe '::Profile' do - describe '#has_achievements?' do - it 'is true when there are achievements' do - nonprofit = build(:nonprofit, achievements: ['Achieve']) + describe "::Profile" do + describe "#has_achievements?" do + it "is true when there are achievements" do + nonprofit = build(:nonprofit, achievements: ["Achieve"]) expect(nonprofit).to be_has_achievements end - - it 'is false when achievements is empty array' do - nonprofit = build(:nonprofit, achievements:[]) + + it "is false when achievements is empty array" do + nonprofit = build(:nonprofit, achievements: []) expect(nonprofit).to_not be_has_achievements end - it 'is false when achievements is nil' do - nonprofit = build(:nonprofit, achievements:nil) + it "is false when achievements is nil" do + nonprofit = build(:nonprofit, achievements: nil) expect(nonprofit).to_not be_has_achievements end - it 'is false when achievements is not an array' do - nonprofit = build(:nonprofit, achievements:{}) + it "is false when achievements is not an array" do + nonprofit = build(:nonprofit, achievements: {}) expect(nonprofit).to_not be_has_achievements end end end - describe '::PathCaching' do - - describe 'after save' do - it 'runs clear_cache after create' do + describe "::PathCaching" do + describe "after save" do + it "runs clear_cache after create" do np = build(:nonprofit) expect(np).to receive(:clear_cache).at_least(:once) np.save! end - it 'runs clear_cache after update' do + it "runs clear_cache after update" do np = create(:nonprofit) expect(np).to receive(:clear_cache) @@ -609,20 +594,20 @@ end end - describe '#clear_cache' do - it 'calls the .clear_caching class method' do + describe "#clear_cache" do + it "calls the .clear_caching class method" do np = create(:nonprofit) expect(Nonprofit).to receive(:clear_caching).with(np.id, np.state_code_slug, np.city_slug, np.slug) np.clear_cache end end - describe '.clear_caching' do - it 'clears the proper cache keys' do + describe ".clear_caching" do + it "clears the proper cache keys" do id = 1 - state_code = 'wi' - city = 'appleton' - name = 'another-org' + state_code = "wi" + city = "appleton" + name = "another-org" expect(Rails.cache).to receive(:delete).with("nonprofit__CACHE_KEY__ID___#{id}") expect(Rails.cache).to receive(:delete).with("nonprofit__CACHE_KEY__LOCATION___#{state_code}____#{city}___#{name}") @@ -632,43 +617,43 @@ end end - describe '.create_cache_key_for_id' do - it 'creates an accurate cache key' do + describe ".create_cache_key_for_id" do + it "creates an accurate cache key" do expect(described_class.create_cache_key_for_id(1234)) - .to eq('nonprofit__CACHE_KEY__ID___1234') + .to eq("nonprofit__CACHE_KEY__ID___1234") end end - describe '.create_cache_key_for_location' do - it 'creates an accurate cache key' do - expect(described_class.create_cache_key_for_location('wi', 'appleton', 'another-org')) - .to eq('nonprofit__CACHE_KEY__LOCATION___wi____appleton___another-org') + describe ".create_cache_key_for_location" do + it "creates an accurate cache key" do + expect(described_class.create_cache_key_for_location("wi", "appleton", "another-org")) + .to eq("nonprofit__CACHE_KEY__LOCATION___wi____appleton___another-org") end end - describe '.find_via_cached_id' do - it 'finds the correct nonprofit' do + describe ".find_via_cached_id" do + it "finds the correct nonprofit" do np = create(:nonprofit) expect(Rails.cache).to receive(:fetch).with("nonprofit__CACHE_KEY__ID___#{np.id}", expires_in: 4.hours).and_yield expect(Nonprofit.find_via_cached_id(np.id)).to eq np end - it 'raises ActiveRecord::RecordNotFound when no valid nonprofit exists' do + it "raises ActiveRecord::RecordNotFound when no valid nonprofit exists" do expect(Rails.cache).to receive(:fetch).with("nonprofit__CACHE_KEY__ID___5555", expires_in: 4.hours).and_yield - expect{ Nonprofit.find_via_cached_id(5555)}.to raise_error(ActiveRecord::RecordNotFound) + expect { Nonprofit.find_via_cached_id(5555) }.to raise_error(ActiveRecord::RecordNotFound) end end - describe '.find_via_cached_key_for_location' do - it 'finds the correct nonprofit' do + describe ".find_via_cached_key_for_location" do + it "finds the correct nonprofit" do np = create(:nonprofit) expect(Rails.cache).to receive(:fetch).with("nonprofit__CACHE_KEY__LOCATION___#{np.state_code_slug}____#{np.city_slug}___#{np.slug}", expires_in: 4.hours).and_yield expect(Nonprofit.find_via_cached_key_for_location(np.state_code_slug, np.city_slug, np.slug)).to eq np end - it 'returns nil when no valid nonprofit exists' do + it "returns nil when no valid nonprofit exists" do state_code_slug = "wi" city_slug = "green-bay" slug = "one-more-org" @@ -679,14 +664,13 @@ end describe "#payments" do - - let(:nonprofit) { create(:nonprofit_base)} - let(:supporter) { create(:supporter_base, nonprofit:nonprofit)} - let(:payment1) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 1.second)} - let(:payment2) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 7.hours)} # this is after midnight at Central Time - let(:payment3){ create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.end_of_year + 1.second)} # this is before midnight at Central Time but after UTC - - before(:each) do + let(:nonprofit) { create(:nonprofit_base) } + let(:supporter) { create(:supporter_base, nonprofit: nonprofit) } + let(:payment1) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 1.second) } + let(:payment2) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 7.hours) } # this is after midnight at Central Time + let(:payment3) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.end_of_year + 1.second) } # this is before midnight at Central Time but after UTC + + before(:each) do payment1 payment2 payment3 @@ -706,7 +690,7 @@ describe "#prior_to_np_year" do it "has no payments when nonprofit has UTC time zone" do - expect(nonprofit.payments.prior_to_np_year(Time.new.utc.year)).to contain_exactly() + expect(nonprofit.payments.prior_to_np_year(Time.new.utc.year)).to contain_exactly end it "has 1 payment when nonprofit has Central time zone" do @@ -717,16 +701,15 @@ end end - describe "#supporters_who_have_payments_during_year" do - let(:nonprofit) { create(:nonprofit_base)} - let(:supporter) { create(:supporter_base, nonprofit:nonprofit)} - let(:supporter2) { create(:supporter_base, nonprofit:nonprofit)} - let(:payment1) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 1.second)} - let(:payment2) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 7.hours)} # this is after midnight at Central Time - let(:payment3){ create(:payment_base, :with_offline_payment, supporter: supporter2, nonprofit: nonprofit, date: Time.new.utc.end_of_year + 1.second)} # this is before midnight at Central Time but after UTC - - before(:each) do + let(:nonprofit) { create(:nonprofit_base) } + let(:supporter) { create(:supporter_base, nonprofit: nonprofit) } + let(:supporter2) { create(:supporter_base, nonprofit: nonprofit) } + let(:payment1) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 1.second) } + let(:payment2) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 7.hours) } # this is after midnight at Central Time + let(:payment3) { create(:payment_base, :with_offline_payment, supporter: supporter2, nonprofit: nonprofit, date: Time.new.utc.end_of_year + 1.second) } # this is before midnight at Central Time but after UTC + + before(:each) do payment1 payment2 payment3 @@ -738,9 +721,9 @@ end describe "#supporters" do - [ - :email, - :name, + [ + :email, + :name, :name_and_email, :name_and_phone, :name_and_phone_and_address, @@ -749,26 +732,25 @@ :phone_and_email, :address_without_zip_code ].each do |type| - method_name = "dupes_on_#{type.to_s}" - let(:nonprofit) {build(:nonprofit, id: 1)} - + method_name = "dupes_on_#{type}" + let(:nonprofit) { build(:nonprofit, id: 1) } + describe "##{method_name}" do - it 'is calls with strict_mode default of true' do + it "is calls with strict_mode default of true" do expect(QuerySupporters).to receive(method_name.to_sym).with(1, true) nonprofit.supporters.send(method_name.to_sym) end - it 'is calls with strict_mode passed of true' do + it "is calls with strict_mode passed of true" do expect(QuerySupporters).to receive(method_name.to_sym).with(1, true) nonprofit.supporters.send(method_name.to_sym, true) end - it 'is calls with strict_mode passed of false' do + it "is calls with strict_mode passed of false" do expect(QuerySupporters).to receive(method_name.to_sym).with(1, false) nonprofit.supporters.send(method_name.to_sym, false) end end end - end end diff --git a/spec/models/object_event_spec.rb b/spec/models/object_event_spec.rb index 8d74a00f7..b3caf362e 100644 --- a/spec/models/object_event_spec.rb +++ b/spec/models/object_event_spec.rb @@ -1,22 +1,21 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe ObjectEvent, type: :model do - it_behaves_like 'an houidable entity', :evt + it_behaves_like "an houidable entity", :evt - around(:each) {|ex| - Timecop.freeze(Time.new(2020, 5, 4)) do + around(:each) { |ex| + Timecop.freeze(Time.new(2020, 5, 4)) do ex.run end } - let(:simple_object_with_parent) { create(:simple_object_with_parent)} + let(:simple_object_with_parent) { create(:simple_object_with_parent) } let(:evt) { simple_object_with_parent.publish_created - } - describe 'after_save is accurate' do - subject(:event) { evt} + describe "after_save is accurate" do + subject(:event) { evt } it { is_expected.to be_persisted } @@ -24,39 +23,38 @@ it { is_expected.to have_attributes( houid: match_houid("evt"), - event_type: 'simple_object.created', + event_type: "simple_object.created", event_entity: simple_object_with_parent, created: Time.new(2020, 5, 4) ) } - describe 'json' do - subject(:json) { event.object_json} + describe "json" do + subject(:json) { event.object_json } it { is_expected.to include( - 'id' => match_houid("evt"), - 'type' => 'simple_object.created', - 'object' => "object_event", - 'created' => Time.new(2020, 5, 4).to_i + "id" => match_houid("evt"), + "type" => "simple_object.created", + "object" => "object_event", + "created" => Time.new(2020, 5, 4).to_i ) } - describe '-> data' do - subject(:data) {json['data']} - describe '-> object' do - subject(:object) { data['object']} + describe "-> data" do + subject(:data) { json["data"] } + describe "-> object" do + subject(:object) { data["object"] } it { is_expected.to include( - 'id' => simple_object_with_parent.houid, - 'object' => "simple_object", - 'friends' => all(be_an(Integer)), - 'parent' => be_a(Hash) + "id" => simple_object_with_parent.houid, + "object" => "simple_object", + "friends" => all(be_an(Integer)), + "parent" => be_a(Hash) ) } end end - end end end diff --git a/spec/models/offline_transaction_charge_spec.rb b/spec/models/offline_transaction_charge_spec.rb index 9201b4002..6d525a7b1 100644 --- a/spec/models/offline_transaction_charge_spec.rb +++ b/spec/models/offline_transaction_charge_spec.rb @@ -2,12 +2,12 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe OfflineTransactionCharge, type: :model do - it_behaves_like 'subtransaction paymentable', :offtrxchrg + it_behaves_like "subtransaction paymentable", :offtrxchrg - it { - is_expected.to have_one(:offsite_payment).through(:legacy_payment) - } + it { + is_expected.to have_one(:offsite_payment).through(:legacy_payment) + } end diff --git a/spec/models/offline_transaction_spec.rb b/spec/models/offline_transaction_spec.rb index 7a3148c83..e7f994143 100644 --- a/spec/models/offline_transaction_spec.rb +++ b/spec/models/offline_transaction_spec.rb @@ -2,8 +2,8 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe OfflineTransaction, type: :model do - it_behaves_like 'subtransactable', :offlinetrx, :offline_transaction_for_testing_payment_extensions + it_behaves_like "subtransactable", :offlinetrx, :offline_transaction_for_testing_payment_extensions end diff --git a/spec/models/offsite_payment_spec.rb b/spec/models/offsite_payment_spec.rb index fb77283c5..daafa0f7a 100644 --- a/spec/models/offsite_payment_spec.rb +++ b/spec/models/offsite_payment_spec.rb @@ -1,11 +1,11 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe OffsitePayment, type: :model do - it {is_expected.to have_db_column(:gross_amount).of_type(:integer)} - it {is_expected.to have_db_column(:kind).of_type(:string)} - it {is_expected.to have_db_column(:date).of_type(:datetime)} - it {is_expected.to have_db_column(:check_number).of_type(:string)} + it { is_expected.to have_db_column(:gross_amount).of_type(:integer) } + it { is_expected.to have_db_column(:kind).of_type(:string) } + it { is_expected.to have_db_column(:date).of_type(:datetime) } + it { is_expected.to have_db_column(:check_number).of_type(:string) } it { is_expected.to belong_to(:payment) } it { is_expected.to belong_to(:donation) } diff --git a/spec/models/payment_dupe_status_spec.rb b/spec/models/payment_dupe_status_spec.rb index 830fe13bc..a95bfbf1c 100644 --- a/spec/models/payment_dupe_status_spec.rb +++ b/spec/models/payment_dupe_status_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe PaymentDupeStatus, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/payment_spec.rb b/spec/models/payment_spec.rb index 8ea26bdf0..840bb2d50 100644 --- a/spec/models/payment_spec.rb +++ b/spec/models/payment_spec.rb @@ -1,232 +1,229 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe Payment, :type => :model do +RSpec.describe Payment, type: :model do it { - is_expected.to have_one(:subtransaction_payment).with_foreign_key('legacy_payment_id').inverse_of(:legacy_payment) + is_expected.to have_one(:subtransaction_payment).with_foreign_key("legacy_payment_id").inverse_of(:legacy_payment) } it { - is_expected.to have_one(:trx).class_name('Transaction').through(:subtransaction_payment) + is_expected.to have_one(:trx).class_name("Transaction").through(:subtransaction_payment) } - it {is_expected.to have_one( :manual_balance_adjustment)} + it { is_expected.to have_one(:manual_balance_adjustment) } it { is_expected.to have_many(:campaign_gifts).through(:donation) } - describe '#staff_comment' do - it 'is nil if manual_balance_adjustment is unset' do + describe "#staff_comment" do + it "is nil if manual_balance_adjustment is unset" do payment = build(:payment) expect(payment.staff_comment).to be_nil end - it 'is nil if manual_balance_adjustment.staff_comment is nil' do - payment = build(:payment, manual_balance_adjustment: build( :manual_balance_adjustment)) + it "is nil if manual_balance_adjustment.staff_comment is nil" do + payment = build(:payment, manual_balance_adjustment: build(:manual_balance_adjustment)) expect(payment.staff_comment).to be_nil end - it 'is nil if manual_balance_adjustment.staff_comment is blank' do - payment = build(:payment, manual_balance_adjustment: build( :manual_balance_adjustment, staff_comment: ' ')) + it "is nil if manual_balance_adjustment.staff_comment is blank" do + payment = build(:payment, manual_balance_adjustment: build(:manual_balance_adjustment, staff_comment: " ")) expect(payment.staff_comment).to be_nil end - it 'proxies manual_balance_adjustment.staff_comment when filled' do - + it "proxies manual_balance_adjustment.staff_comment when filled" do staff_comment = "refund of fees" - payment = build(:payment, manual_balance_adjustment: build( :manual_balance_adjustment, staff_comment: staff_comment)) + payment = build(:payment, manual_balance_adjustment: build(:manual_balance_adjustment, staff_comment: staff_comment)) expect(payment.staff_comment).to eq staff_comment end end - - describe '.activities' do - describe 'Dispute' do + + describe ".activities" do + describe "Dispute" do shared_context :common_specs do - let(:activity_json) { activity.json_data} - specify { expect(activity.supporter).to eq supporter} - specify { expect(activity.nonprofit).to eq nonprofit} - specify { expect(activity_json['status']).to eq dispute.status } - specify { expect(activity_json['reason']).to eq dispute.reason } - specify { expect(activity_json['original_id']).to eq charge.payment.id} - specify { expect(activity_json['original_kind']).to eq charge.payment.kind} - specify { expect(activity_json['original_gross_amount']).to eq charge.payment.gross_amount} - specify { expect(activity_json['original_date']).to eq charge.payment.date} + let(:activity_json) { activity.json_data } + specify { expect(activity.supporter).to eq supporter } + specify { expect(activity.nonprofit).to eq nonprofit } + specify { expect(activity_json["status"]).to eq dispute.status } + specify { expect(activity_json["reason"]).to eq dispute.reason } + specify { expect(activity_json["original_id"]).to eq charge.payment.id } + specify { expect(activity_json["original_kind"]).to eq charge.payment.kind } + specify { expect(activity_json["original_gross_amount"]).to eq charge.payment.gross_amount } + specify { expect(activity_json["original_date"]).to eq charge.payment.date } end - + describe "dispute.funds_withdrawn" do include_context :dispute_funds_withdrawn_context include_context :common_specs - let(:obj) { StripeDispute.create(object:json) } - let(:activity) { withdrawal_payment.activities.build} - - specify { expect(activity.kind).to eq 'DisputeFundsWithdrawn'} - specify { expect(activity.date).to eq withdrawal_payment.date} - specify { expect(activity_json['gross_amount']).to eq withdrawal_payment.gross_amount } - specify { expect(activity_json['fee_total']).to eq withdrawal_payment.fee_total } - specify { expect(activity_json['net_amount']).to eq withdrawal_payment.net_amount } + let(:obj) { StripeDispute.create(object: json) } + let(:activity) { withdrawal_payment.activities.build } + + specify { expect(activity.kind).to eq "DisputeFundsWithdrawn" } + specify { expect(activity.date).to eq withdrawal_payment.date } + specify { expect(activity_json["gross_amount"]).to eq withdrawal_payment.gross_amount } + specify { expect(activity_json["fee_total"]).to eq withdrawal_payment.fee_total } + specify { expect(activity_json["net_amount"]).to eq withdrawal_payment.net_amount } end - - # describe "dispute.created AND funds_withdrawn at same time" do + + # describe "dispute.created AND funds_withdrawn at same time" do # include_context :dispute_created_and_withdrawn_at_same_time_specs - # let(:obj) do + # let(:obj) do # sd = StripeDispute.create(object:json_created) # sd.object = json_funds_withdrawn # sd.save! # sd # end # end - - # describe "dispute.created AND funds_withdrawn in order" do + + # describe "dispute.created AND funds_withdrawn in order" do # include_context :dispute_created_and_withdrawn_in_order_specs - # let(:obj) do + # let(:obj) do # sd = StripeDispute.create(object:json_created) # sd.object = json_funds_withdrawn # sd.save! # sd # end # end - + describe "dispute.funds_reinstated" do include_context :dispute_funds_reinstated_context include_context :common_specs - let(:obj) { StripeDispute.create(object:json) } - let(:activity) { reinstated_payment.activities.build} + let(:obj) { StripeDispute.create(object: json) } + let(:activity) { reinstated_payment.activities.build } - specify { expect(activity.kind).to eq 'DisputeFundsReinstated'} + specify { expect(activity.kind).to eq "DisputeFundsReinstated" } specify { expect(activity.date).to eq reinstated_payment.date } - specify { expect(activity_json['gross_amount']).to eq reinstated_payment.gross_amount } - specify { expect(activity_json['fee_total']).to eq reinstated_payment.fee_total } - specify { expect(activity_json['net_amount']).to eq reinstated_payment.net_amount } + specify { expect(activity_json["gross_amount"]).to eq reinstated_payment.gross_amount } + specify { expect(activity_json["fee_total"]).to eq reinstated_payment.fee_total } + specify { expect(activity_json["net_amount"]).to eq reinstated_payment.net_amount } end - + # describe "dispute.closed, status = lost" do # include_context :dispute_lost_specs - + # let(:obj) { StripeDispute.create(object:json) } # end end end - describe '.anonymous' do - it 'has no payments when none are anonymous' do + describe ".anonymous" do + it "has no payments when none are anonymous" do create(:fv_poverty_payment) expect(Payment.anonymous.count).to eq 0 end - it 'has 1 payment when donation is anonymous' do + it "has 1 payment when donation is anonymous" do create(:fv_poverty_payment, :anonymous_through_donation) expect(Payment.anonymous.count).to eq 1 end - it 'has 1 payment when supporter is anonymous' do + it "has 1 payment when supporter is anonymous" do create(:fv_poverty_payment, :anonymous_through_supporter) expect(Payment.anonymous.count).to eq 1 end - it 'has 1 payment when both supporter and donation are anonymous' do - create(:fv_poverty_payment, :anonymous_through_supporter, :anonymous_through_donation) + it "has 1 payment when both supporter and donation are anonymous" do + create(:fv_poverty_payment, :anonymous_through_supporter, :anonymous_through_donation) expect(Payment.anonymous.count).to eq 1 end end - describe '.not_anonymous' do - - it 'has 1 payment when none are anonymous' do + describe ".not_anonymous" do + it "has 1 payment when none are anonymous" do create(:fv_poverty_payment) expect(Payment.not_anonymous.count).to eq 1 end - it 'has no payments when donation is anonymous' do + it "has no payments when donation is anonymous" do create(:fv_poverty_payment, :anonymous_through_donation) expect(Payment.not_anonymous.count).to eq 0 end - it 'has no payments when supporter is anonymous' do + it "has no payments when supporter is anonymous" do create(:fv_poverty_payment, :anonymous_through_supporter) expect(Payment.not_anonymous.count).to eq 0 end - it 'has no payments when both supporter and donation are anonymous' do + it "has no payments when both supporter and donation are anonymous" do create(:fv_poverty_payment, :anonymous_through_supporter, :anonymous_through_donation) expect(Payment.not_anonymous.count).to eq 0 end end - describe '#consider_anonymous?' do - it 'is false when none are anonymous' do + describe "#consider_anonymous?" do + it "is false when none are anonymous" do expect(create(:fv_poverty_payment)).to_not be_consider_anonymous end - it 'is true when donation is anonymous' do + it "is true when donation is anonymous" do expect(create(:fv_poverty_payment, :anonymous_through_donation)).to be_consider_anonymous end - it 'is true when supporter is anonymous' do + it "is true when supporter is anonymous" do expect(create(:fv_poverty_payment, :anonymous_through_supporter)).to be_consider_anonymous end - it 'is true when both supporter and donation are anonymous' do - expect(create(:fv_poverty_payment, :anonymous_through_supporter, :anonymous_through_donation)).to be_consider_anonymous + it "is true when both supporter and donation are anonymous" do + expect(create(:fv_poverty_payment, :anonymous_through_supporter, :anonymous_through_donation)).to be_consider_anonymous end end - describe '#from_donation?' do - + describe "#from_donation?" do context "for kind == 'Refund" do - it 'is true when refund came from donation' do - expect(build(:payment, kind: 'Refund', refund: build(:refund, :from_donation)).from_donation?).to eq true + it "is true when refund came from donation" do + expect(build(:payment, kind: "Refund", refund: build(:refund, :from_donation)).from_donation?).to eq true end - it 'is false when refund didnt come from donation' do - expect(build(:payment, kind: 'Refund', refund: build(:refund, :not_from_donation)).from_donation?).to eq false + it "is false when refund didnt come from donation" do + expect(build(:payment, kind: "Refund", refund: build(:refund, :not_from_donation)).from_donation?).to eq false end end context "for kind == 'Dispute" do - it 'is true when dispute came from donation' do - expect(build(:payment, kind: 'Dispute', dispute_transaction: build(:dispute_transaction, :from_donation)).from_donation?).to eq true + it "is true when dispute came from donation" do + expect(build(:payment, kind: "Dispute", dispute_transaction: build(:dispute_transaction, :from_donation)).from_donation?).to eq true end - it 'is false when dispute didnt come from donation' do - expect(build(:payment, kind: 'Dispute', dispute_transaction: build(:dispute_transaction, :not_from_donation)).from_donation?).to eq false + it "is false when dispute didnt come from donation" do + expect(build(:payment, kind: "Dispute", dispute_transaction: build(:dispute_transaction, :not_from_donation)).from_donation?).to eq false end end context "for kind == 'DisputeReversal" do - it 'is true when dispute_reversal came from donation' do - expect(build(:payment, kind: 'DisputeReversal', dispute_transaction: build(:dispute_transaction, :from_donation)).from_donation?).to eq true + it "is true when dispute_reversal came from donation" do + expect(build(:payment, kind: "DisputeReversal", dispute_transaction: build(:dispute_transaction, :from_donation)).from_donation?).to eq true end - it 'is false when dispute didnt come from donation' do - expect(build(:payment, kind: 'DisputeReversal', dispute_transaction: build(:dispute_transaction, :not_from_donation)).from_donation?).to eq false + it "is false when dispute didnt come from donation" do + expect(build(:payment, kind: "DisputeReversal", dispute_transaction: build(:dispute_transaction, :not_from_donation)).from_donation?).to eq false end end context "for kind == 'OffsitePayment" do - it 'is true when donation is set' do - expect(build(:payment, kind: 'OffsitePayment', donation: build(:donation)).from_donation?).to eq true + it "is true when donation is set" do + expect(build(:payment, kind: "OffsitePayment", donation: build(:donation)).from_donation?).to eq true end - it 'is false when donation is not set' do - expect(build(:payment, kind: 'OffsitePayment').from_donation?).to eq false + it "is false when donation is not set" do + expect(build(:payment, kind: "OffsitePayment").from_donation?).to eq false end end context "for kind == 'Donation" do - it 'is true' do - expect(build(:payment, kind: 'Donation').from_donation?).to eq true + it "is true" do + expect(build(:payment, kind: "Donation").from_donation?).to eq true end end context "for kind == 'RecurringDonation" do - it 'is true' do - expect(build(:payment, kind: 'RecurringDonation').from_donation?).to eq true + it "is true" do + expect(build(:payment, kind: "RecurringDonation").from_donation?).to eq true end end context "for kind == 'FakeKind'" do - it 'is false' do - expect(build(:payment, kind: 'FakeKind').from_donation?).to eq false + it "is false" do + expect(build(:payment, kind: "FakeKind").from_donation?).to eq false end end end -end \ No newline at end of file +end diff --git a/spec/models/payout_spec.rb b/spec/models/payout_spec.rb index 0b8a2a55a..a8cb672b6 100644 --- a/spec/models/payout_spec.rb +++ b/spec/models/payout_spec.rb @@ -1,46 +1,46 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe Payout, :type => :model do +RSpec.describe Payout, type: :model do # We need a bank and stripe account connected to the Payout for validation to pass let(:bank_account) do - ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token(), name: Faker::Bank.name}) + ba = InsertBankAccount.with_stripe(nonprofit, user, {stripe_bank_account_token: StripeMockHelper.generate_bank_token, name: Faker::Bank.name}) ba.pending_verification = false ba.save ba end - let(:stripe_account) do + let(:stripe_account) do force_create(:stripe_account, stripe_account_id: nonprofit.stripe_account_id, payouts_enabled: true) end - let(:nonprofit) {force_create(:nonprofit, :stripe_account_id => Stripe::Account.create()['id'], vetted: true)} + let(:nonprofit) { force_create(:nonprofit, stripe_account_id: Stripe::Account.create["id"], vetted: true) } let(:payout) { create(:payout, nonprofit: nonprofit) } - let(:user) {force_create(:user)} - - it {is_expected.to have_db_column(:net_amount)} - it {is_expected.to have_db_column(:failure_message)} - it {is_expected.to have_db_column(:status)} - it {is_expected.to have_db_column(:fee_total)} - it {is_expected.to have_db_column(:gross_amount)} - it {is_expected.to have_db_column(:bank_name)} - it {is_expected.to have_db_column(:email)} - it {is_expected.to have_db_column(:count)} - it {is_expected.to have_db_column(:manual)} - it {is_expected.to have_db_column(:scheduled)} - it {is_expected.to have_db_column(:stripe_transfer_id)} - it {is_expected.to have_db_column(:user_ip)} - - it {is_expected.to belong_to(:nonprofit)} - it {is_expected.to have_one(:bank_account).through(:nonprofit)} - it {is_expected.to have_many(:payment_payouts)} - it {is_expected.to have_many(:payments).through(:payment_payouts)} - it {is_expected.to have_many(:object_events)} - - it {is_expected.to validate_presence_of(:stripe_transfer_id)} - it {is_expected.to validate_uniqueness_of(:stripe_transfer_id)} - it {is_expected.to validate_presence_of(:nonprofit)} - it {is_expected.to validate_presence_of(:bank_account)} - it {is_expected.to validate_presence_of(:email)} - it {is_expected.to validate_presence_of(:net_amount)} + let(:user) { force_create(:user) } + + it { is_expected.to have_db_column(:net_amount) } + it { is_expected.to have_db_column(:failure_message) } + it { is_expected.to have_db_column(:status) } + it { is_expected.to have_db_column(:fee_total) } + it { is_expected.to have_db_column(:gross_amount) } + it { is_expected.to have_db_column(:bank_name) } + it { is_expected.to have_db_column(:email) } + it { is_expected.to have_db_column(:count) } + it { is_expected.to have_db_column(:manual) } + it { is_expected.to have_db_column(:scheduled) } + it { is_expected.to have_db_column(:stripe_transfer_id) } + it { is_expected.to have_db_column(:user_ip) } + + it { is_expected.to belong_to(:nonprofit) } + it { is_expected.to have_one(:bank_account).through(:nonprofit) } + it { is_expected.to have_many(:payment_payouts) } + it { is_expected.to have_many(:payments).through(:payment_payouts) } + it { is_expected.to have_many(:object_events) } + + it { is_expected.to validate_presence_of(:stripe_transfer_id) } + it { is_expected.to validate_uniqueness_of(:stripe_transfer_id) } + it { is_expected.to validate_presence_of(:nonprofit) } + it { is_expected.to validate_presence_of(:bank_account) } + it { is_expected.to validate_presence_of(:email) } + it { is_expected.to validate_presence_of(:net_amount) } it { StripeMockHelper.mock do @@ -52,9 +52,9 @@ end } - it {is_expected.to delegate_method(:currency).to(:nonprofit)} - - it_behaves_like 'an houidable entity', :pyout, :houid + it { is_expected.to delegate_method(:currency).to(:nonprofit) } - it_behaves_like 'an object with as_money attributes', :net_amount + it_behaves_like "an houidable entity", :pyout, :houid + + it_behaves_like "an object with as_money attributes", :net_amount end diff --git a/spec/models/periodic_report_spec.rb b/spec/models/periodic_report_spec.rb index 84e387f6a..187adbaf5 100644 --- a/spec/models/periodic_report_spec.rb +++ b/spec/models/periodic_report_spec.rb @@ -1,95 +1,94 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe PeriodicReport, type: :model do let(:nonprofit) { create(:nonprofit_base) } - let(:user) { create(:user, roles: [build(:role, name: 'nonprofit_associate', host: nonprofit)]) } + let(:user) { create(:user, roles: [build(:role, name: "nonprofit_associate", host: nonprofit)]) } let(:users_list) { User.where(id: user.id) } - it {is_expected.to belong_to(:nonprofit).required(true)} - it {is_expected.to belong_to(:nonprofit_s3_key)} + it { is_expected.to belong_to(:nonprofit).required(true) } + it { is_expected.to belong_to(:nonprofit_s3_key) } - describe '#validation' do + describe "#validation" do let(:attributes) do { - :active => true, - :report_type => :failed_recurring_donations, - :period => :last_month, - :users => users_list + active: true, + report_type: :failed_recurring_donations, + period: :last_month, + users: users_list } end subject { nonprofit.periodic_reports.create(attributes) } - it 'is valid if it has the correct attributes' do + it "is valid if it has the correct attributes" do periodic_report = subject expect(periodic_report.valid?).to be_truthy end - it 'is not valid if it does not have a supported report_type' do + it "is not valid if it does not have a supported report_type" do attributes[:report_type] = :invalid_report_type periodic_report = subject expect(periodic_report.valid?).to be_falsy end - it 'is not valid if it does not have a supported period' do + it "is not valid if it does not have a supported period" do attributes[:period] = :invalid_period periodic_report = subject expect(periodic_report.valid?).to be_falsy end - it 'is not valid if it the nonprofit on nonprofit_s3_key does not match nonprofit' do + it "is not valid if it the nonprofit on nonprofit_s3_key does not match nonprofit" do attributes[:nonprofit_s3_key] = create(:nonprofit_s3_key) periodic_report = subject expect(periodic_report.valid?).to be_falsy end - it 'is valid if it the nonprofit on nonprofit_s3_key does match nonprofit' do + it "is valid if it the nonprofit on nonprofit_s3_key does match nonprofit" do attributes[:nonprofit_s3_key] = create(:nonprofit_s3_key, nonprofit: nonprofit) periodic_report = subject expect(periodic_report.valid?).to be_truthy - end - context 'users validation' do - it 'is not valid if user does not belong to given nonprofit' do + context "users validation" do + it "is not valid if user does not belong to given nonprofit" do attributes[:users] = [create(:user)] periodic_report = subject expect(periodic_report.valid?).to be_falsy end - it 'is not valid if a list of users is not provided' do + it "is not valid if a list of users is not provided" do attributes[:users] = [] periodic_report = subject expect(periodic_report.valid?).to be_falsy end - it 'is valid if the user provided is a super admin' do - attributes[:users] = [create(:user, roles: [build(:role, name: 'super_admin')])] + it "is valid if the user provided is a super admin" do + attributes[:users] = [create(:user, roles: [build(:role, name: "super_admin")])] periodic_report = subject expect(periodic_report.valid?).to be_truthy end end end - describe 'scopes' do - describe '#active' do + describe "scopes" do + describe "#active" do let(:attributes) do [{ - :active => true, - :report_type => :failed_recurring_donations, - :period => :last_month, - :users => users_list + active: true, + report_type: :failed_recurring_donations, + period: :last_month, + users: users_list }, { - :active => true, - :report_type => :failed_recurring_donations, - :period => :last_month, - :users => users_list + active: true, + report_type: :failed_recurring_donations, + period: :last_month, + users: users_list }, { - :active => false, - :report_type => :failed_recurring_donations, - :period => :last_month, - :users => users_list + active: false, + report_type: :failed_recurring_donations, + period: :last_month, + users: users_list }] end @@ -101,28 +100,27 @@ end end - it 'finds active periodic reports' do + it "finds active periodic reports" do expect(subject.count).to eq(2) end end end - describe '#run' do - + describe "#run" do it { is_expected.to delegate_method(:run).to(:adapter) } - context 'when the report is for failed recurring donations' do + context "when the report is for failed recurring donations" do let(:attributes) do { - :active => true, - :report_type => 'failed_recurring_donations', - :period => 'last_month', - :users => users_list, + active: true, + report_type: "failed_recurring_donations", + period: "last_month", + users: users_list, nonprofit_s3_key: nil, filename: nil } end - let(:options) { attributes.except(:active).merge({ :nonprofit_id => nonprofit.id }) } + let(:options) { attributes.except(:active).merge({nonprofit_id: nonprofit.id}) } let(:failed_recurring_donations_report) { double } @@ -133,24 +131,24 @@ .and_return(failed_recurring_donations_report) end - it 'calls the correct corresponding adapter' do + it "calls the correct corresponding adapter" do expect(failed_recurring_donations_report).to receive(:run) nonprofit.periodic_reports.create(attributes).run end end - context 'when the report is for cancelled recurring donations' do + context "when the report is for cancelled recurring donations" do let(:attributes) do { - :active => true, - :report_type => 'cancelled_recurring_donations', - :period => 'last_month', - :users => users_list, + active: true, + report_type: "cancelled_recurring_donations", + period: "last_month", + users: users_list, nonprofit_s3_key: nil, filename: nil } end - let(:options) { attributes.except(:active).merge({ :nonprofit_id => nonprofit.id }) } + let(:options) { attributes.except(:active).merge({nonprofit_id: nonprofit.id}) } let(:cancelled_recurring_donations_report) { double } @@ -161,7 +159,7 @@ .and_return(cancelled_recurring_donations_report) end - it 'calls the correct corresponding adapter' do + it "calls the correct corresponding adapter" do expect(cancelled_recurring_donations_report).to receive(:run) nonprofit.periodic_reports.create(attributes).run end diff --git a/spec/models/reassignment_spec.rb b/spec/models/reassignment_spec.rb index aad0ecc77..079e64e4e 100644 --- a/spec/models/reassignment_spec.rb +++ b/spec/models/reassignment_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe Reassignment, type: :model do pending "add some examples to (or delete) #{__FILE__}" diff --git a/spec/models/recurring_donation_spec.rb b/spec/models/recurring_donation_spec.rb index 4a6b8f119..0335b87f4 100644 --- a/spec/models/recurring_donation_spec.rb +++ b/spec/models/recurring_donation_spec.rb @@ -1,91 +1,86 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe RecurringDonation, type: :model do before(:each) do ActiveJob::Base.queue_adapter = :test end - describe 'commonly used values' do - let!(:cancelled) { force_create(:recurring_donation, active:false, n_failures: 0)} + describe "commonly used values" do + let!(:cancelled) { force_create(:recurring_donation, active: false, n_failures: 0) } - let!(:failed) { force_create(:recurring_donation, active:true, n_failures: 3)} + let!(:failed) { force_create(:recurring_donation, active: true, n_failures: 3) } - let!(:normal) { force_create(:recurring_donation, active:true, n_failures: 2)} + let!(:normal) { force_create(:recurring_donation, active: true, n_failures: 2) } - let!(:ended) { force_create(:recurring_donation, active:true, n_failures: 2, end_date: Time.current - 1.day)} + let!(:ended) { force_create(:recurring_donation, active: true, n_failures: 2, end_date: 1.day.ago) } - let!(:ends_in_future) { force_create(:recurring_donation, active:true, n_failures: 0, end_date: Time.current + 1.day)} - describe '.will_attempt_again?' do - - it 'wont if cancelled' do + let!(:ends_in_future) { force_create(:recurring_donation, active: true, n_failures: 0, end_date: 1.day.from_now) } + describe ".will_attempt_again?" do + it "wont if cancelled" do expect(cancelled).to_not be_will_attempt_again end - it 'wont if failed' do + it "wont if failed" do expect(failed).to_not be_will_attempt_again end - it 'will if not failed or cancelled' do + it "will if not failed or cancelled" do expect(normal).to be_will_attempt_again end - it 'wont if ended' do + it "wont if ended" do expect(ended).to_not be_will_attempt_again end - it 'will if ends in future' do + it "will if ends in future" do expect(ends_in_future).to be_will_attempt_again end end - describe '.may_attempt_again scope' do - subject { RecurringDonation.may_attempt_again} + describe ".may_attempt_again scope" do + subject { RecurringDonation.may_attempt_again } - it { is_expected.to include normal} + it { is_expected.to include normal } - it { is_expected.to_not include cancelled} + it { is_expected.to_not include cancelled } - it { is_expected.to_not include failed} + it { is_expected.to_not include failed } - it { is_expected.to_not include ended} + it { is_expected.to_not include ended } - it {is_expected.to include ends_in_future} + it { is_expected.to include ends_in_future } end end - describe '#cancel!' do + describe "#cancel!" do # it 'requires an email' do # expect{ build_stubbed(:recurring_donation_base).cancel!}.to raise_error ArgumentError # end def uncancelled_recurring_donation - supporter = create(:supporter_base, :with_1_active_mailing_list) nonprofit = supporter.nonprofit donation = create(:donation_base, nonprofit: nonprofit, supporter_id: supporter.id, amount: 999) - recurring_donation = create(:recurring_donation_base, nonprofit: nonprofit, supporter_id: supporter.id, donation: donation) - - recurring_donation + create(:recurring_donation_base, nonprofit: nonprofit, supporter_id: supporter.id, donation: donation) end def cancelled_recurring_donation - supporter = create(:supporter_base, :with_1_active_mailing_list) nonprofit = supporter.nonprofit donation = create(:donation_base, nonprofit: nonprofit, supporter_id: supporter.id, amount: 999) - recurring_donation = create(:recurring_donation_base, nonprofit: nonprofit, supporter_id: supporter.id, donation: donation, active:false, 'cancelled_at' => Time.new(2020, 5, 4), - 'cancelled_by' => "penelope@rebecca.schultz") + create(:recurring_donation_base, :nonprofit => nonprofit, :supporter_id => supporter.id, :donation => donation, :active => false, "cancelled_at" => Time.new(2020, 5, 4), + "cancelled_by" => "penelope@rebecca.schultz") end - it 'cancels an rd properly' do + it "cancels an rd properly" do expect(RecurringDonationCreatedJob).to_not have_been_enqueued recurring_donation = uncancelled_recurring_donation Timecop.freeze Time.new(2020, 5, 4) do recurring_donation.cancel!("penelope@rebecca.schultz") expect(recurring_donation).to have_attributes( - 'active' => false, - 'cancelled_at' => Time.new(2020, 5, 4), - 'cancelled_by' => "penelope@rebecca.schultz" + "active" => false, + "cancelled_at" => Time.new(2020, 5, 4), + "cancelled_by" => "penelope@rebecca.schultz" ) expect(recurring_donation).to be_cancelled @@ -95,7 +90,7 @@ def cancelled_recurring_donation end end - it 'doesnt recancel an already cancelled recurring donation' do + it "doesnt recancel an already cancelled recurring donation" do expect(RecurringDonationCreatedJob).to_not have_been_enqueued expect(RecurringDonationCancelledJob).to_not have_been_enqueued recurring_donation = cancelled_recurring_donation @@ -103,9 +98,9 @@ def cancelled_recurring_donation expect(RecurringDonationCancelledJob).to_not have_been_enqueued recurring_donation.cancel!("eric@david.schultz") expect(recurring_donation).to have_attributes( - 'active' => false, - 'cancelled_at' => Time.new(2020, 5, 4), - 'cancelled_by' => "penelope@rebecca.schultz" + "active" => false, + "cancelled_at" => Time.new(2020, 5, 4), + "cancelled_by" => "penelope@rebecca.schultz" ) expect(recurring_donation).to be_cancelled @@ -115,6 +110,5 @@ def cancelled_recurring_donation expect(RecurringDonationCancelledJob).to_not have_been_enqueued end end - end end diff --git a/spec/models/refund_spec.rb b/spec/models/refund_spec.rb index f6de0b82a..ddbf73324 100644 --- a/spec/models/refund_spec.rb +++ b/spec/models/refund_spec.rb @@ -1,22 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe Refund, type: :model do it { is_expected.to belong_to(:charge) } it { is_expected.to belong_to(:payment) } - it { is_expected.to have_one(:subtransaction_payment).through(:payment)} + it { is_expected.to have_one(:subtransaction_payment).through(:payment) } it { is_expected.to have_one(:misc_refund_info) } it { is_expected.to have_one(:nonprofit).through(:charge) } it { is_expected.to have_one(:supporter).through(:charge) } - it {is_expected.to have_many( :manual_balance_adjustments)} + it { is_expected.to have_many(:manual_balance_adjustments) } describe "#from_donation?" do - it 'is true when refund is associated with a donation' do + it "is true when refund is associated with a donation" do expect(build(:refund, :from_donation).from_donation?).to eq true end - it 'is true when refund is not associated with a donation' do + it "is true when refund is not associated with a donation" do expect(build(:refund, :not_from_donation).from_donation?).to eq false end end diff --git a/spec/models/stripe_account_spec.rb b/spec/models/stripe_account_spec.rb index 7bb08bdaa..cc0867fd4 100644 --- a/spec/models/stripe_account_spec.rb +++ b/spec/models/stripe_account_spec.rb @@ -1,22 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe StripeAccount, :type => :model do +RSpec.describe StripeAccount, type: :model do around(:each) do |example| StripeMockHelper.mock do example.run end end describe "account should be pending" do - let(:sa) do + let(:sa) do create(:stripe_account, :with_pending) end - it 'is pending' do + it "is pending" do expect(sa.verification_status).to eq :pending end - it 'has nil deadline' do + it "has nil deadline" do expect(sa.deadline).to be_nil end end @@ -29,132 +29,129 @@ sa end - it 'is unverified' do + it "is unverified" do expect(sa.verification_status).to eq :unverified end - it 'has deadline of 4 Feb 2020 20:37:19' do + it "has deadline of 4 Feb 2020 20:37:19" do expect(sa.deadline).to eq Time.utc(2020, 2, 28, 22, 27, 35) end end - describe 'account should be unverified' do - let(:sa) do + describe "account should be unverified" do + let(:sa) do create(:stripe_account, :with_unverified) end - it 'is unverified' do + it "is unverified" do expect(sa.verification_status).to eq :unverified end - it 'has nil deadline' do + it "has nil deadline" do expect(sa.deadline).to be_nil end end - describe 'account should be verified' do - - subject(:sa) do + describe "account should be verified" do + subject(:sa) do create(:stripe_account, :with_verified) end - it 'is verified' do + it "is verified" do expect(sa.verification_status).to eq :verified end - it 'has nil deadline' do + it "has nil deadline" do expect(sa.deadline).to be_nil end end - describe 'account should be temporarily verified' do - let(:sa) do + describe "account should be temporarily verified" do + let(:sa) do create(:stripe_account, :with_temporarily_verified) end - it 'is verified' do + it "is verified" do expect(sa.verification_status).to eq :temporarily_verified end - it 'has nil deadline' do + it "has nil deadline" do expect(sa.deadline).to be_nil end end - describe 'account should be unverified because of there is a future_requirements deadline' do - subject(:sa) do + describe "account should be unverified because of there is a future_requirements deadline" do + subject(:sa) do create(:stripe_account, :with_verified_and_bank_provided_but_future_requirements) end - it 'is unverified' do + it "is unverified" do expect(sa.verification_status).to eq :unverified end - it 'has Time.at(1581712639) deadline' do + it "has Time.at(1581712639) deadline" do expect(sa.deadline).to eq Time.at(1581712639) end end - describe 'account should be unverified because of there is a future_requirements deadline' do - subject(:sa) do + describe "account should be unverified because of there is a future_requirements deadline" do + subject(:sa) do create(:stripe_account, :with_verified_and_bank_provided_but_future_requirements_pending) end - it 'is pending' do + it "is pending" do expect(sa.verification_status).to eq :pending end - it 'has Time.at(1581712639) deadline' do + it "has Time.at(1581712639) deadline" do expect(sa.deadline).to eq Time.at(1581712639) end end - describe 'account should be verified because of there is a future_requirements deadline but not values still due' do - subject(:sa) do + describe "account should be verified because of there is a future_requirements deadline but not values still due" do + subject(:sa) do create(:stripe_account, :with_verified_and_bank_provided_with_active_but_empty_future_requirements) end - it 'is verified' do + it "is verified" do expect(sa.verification_status).to eq :verified end - it 'has nil deadline' do + it "has nil deadline" do expect(sa.deadline).to be_nil end end - describe 'account should be unverified because of deadline' do - subject(:sa) do + describe "account should be unverified because of deadline" do + subject(:sa) do create(:stripe_account, :with_temporarily_verified_with_deadline) end - it 'is verified' do + it "is verified" do expect(sa.verification_status).to eq :unverified end - it 'has nil deadline' do + it "has nil deadline" do expect(sa.deadline).to eq Time.at(1580858639) end end - - describe '.without_future_requirements' do - let!(:sa) do + describe ".without_future_requirements" do + let!(:sa) do create(:stripe_account, :without_future_requirements) end - it { expect(StripeAccount.without_future_requirements.count).to eq 1} - it { expect(StripeAccount.with_future_requirements.count).to eq 0} + it { expect(StripeAccount.without_future_requirements.count).to eq 1 } + it { expect(StripeAccount.with_future_requirements.count).to eq 0 } end - describe '.with_future_requirements' do - - let!(:sa) do + describe ".with_future_requirements" do + let!(:sa) do create(:stripe_account, :with_pending) end - it { expect(StripeAccount.without_future_requirements.count).to eq 0} - it { expect(StripeAccount.with_future_requirements.count).to eq 1} + it { expect(StripeAccount.without_future_requirements.count).to eq 0 } + it { expect(StripeAccount.with_future_requirements.count).to eq 1 } end # describe '#future_requirements' do @@ -162,19 +159,19 @@ # create(:stripe_account, :with_pending).future_requirements # } - # it do + # it do # expect(future_requirements.current_deadline).to eq Time.at(1580935094) # end - # it do + # it do # expect(future_requirements.currently_due.count).to eq 8 # end - # it do + # it do # expect(future_requirements.eventually_due.count).to eq 9 # end - # it do + # it do # expect(future_requirements.past_due.count).to eq 6 # end # end diff --git a/spec/models/stripe_charge_spec.rb b/spec/models/stripe_charge_spec.rb index 4847124f9..3adc35667 100644 --- a/spec/models/stripe_charge_spec.rb +++ b/spec/models/stripe_charge_spec.rb @@ -1,10 +1,10 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe StripeCharge, :type => :model do +RSpec.describe StripeCharge, type: :model do describe "charge.succeeded" do include_context :charge_succeeded_specs - - let(:obj) { StripeCharge.create(object:json) } + + let(:obj) { StripeCharge.create(object: json) } end end diff --git a/spec/models/stripe_dispute_spec.rb b/spec/models/stripe_dispute_spec.rb index 183d47154..927a87b36 100644 --- a/spec/models/stripe_dispute_spec.rb +++ b/spec/models/stripe_dispute_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe StripeDispute, :type => :model do +RSpec.describe StripeDispute, type: :model do end diff --git a/spec/models/stripe_event-charge.dispute_spec.rb b/spec/models/stripe_event-charge.dispute_spec.rb index cf905d21f..163099c90 100644 --- a/spec/models/stripe_event-charge.dispute_spec.rb +++ b/spec/models/stripe_event-charge.dispute_spec.rb @@ -1,127 +1,126 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe StripeEvent, :type => :model do +RSpec.describe StripeEvent, type: :model do around(:each) do |example| Timecop.freeze(Date.new(2021, 5, 4)) do - StripeMockHelper.mock do + StripeMockHelper.mock do example.run end end end - - - describe 'charge.dispute.*' do + describe "charge.dispute.*" do describe "dispute.created" do include_context :dispute_created_specs let(:obj) { StripeEvent.process_dispute(event_json) - StripeDispute.where('stripe_dispute_id = ?', json['id']).first + StripeDispute.where("stripe_dispute_id = ?", json["id"]).first } end - + describe "dispute.funds_withdrawn" do include_context :dispute_funds_withdrawn_specs - + let(:obj) do StripeEvent.process_dispute(event_json) - StripeDispute.where('stripe_dispute_id = ?', json['id']).first + StripeDispute.where("stripe_dispute_id = ?", json["id"]).first end end - - describe "dispute.created AND funds_withdrawn at sametime" do + + describe "dispute.created AND funds_withdrawn at sametime" do include_context :dispute_created_and_withdrawn_at_same_time_specs let(:obj) do event_json_funds_withdrawn StripeEvent.process_dispute(event_json_created) StripeEvent.process_dispute(event_json_funds_withdrawn) - StripeDispute.where('stripe_dispute_id = ?', json_funds_withdrawn['id']).first + StripeDispute.where("stripe_dispute_id = ?", json_funds_withdrawn["id"]).first end end - describe "dispute.created AND funds_withdrawn in order" do + describe "dispute.created AND funds_withdrawn in order" do include_context :dispute_created_and_withdrawn_in_order_specs let(:obj) do StripeEvent.process_dispute(event_json_created) StripeEvent.process_dispute(event_json_funds_withdrawn) - StripeDispute.find_by(stripe_dispute_id: json_created['id']) + StripeDispute.find_by(stripe_dispute_id: json_created["id"]) end end - + describe "dispute.funds_reinstated" do include_context :dispute_funds_reinstated_specs - let(:obj) do StripeEvent.process_dispute(event_json) - StripeDispute.where('stripe_dispute_id = ?', json['id']).first + let(:obj) do + StripeEvent.process_dispute(event_json) + StripeDispute.where("stripe_dispute_id = ?", json["id"]).first end end - + describe "dispute.closed, status = lost" do include_context :dispute_lost_specs - + let(:obj) do StripeEvent.process_dispute(event_json) - StripeDispute.where('stripe_dispute_id = ?', json['id']).first + StripeDispute.where("stripe_dispute_id = ?", json["id"]).first end end - + describe "dispute.created -> dispute.funds_withdrawn -> dispute.closed, status = lost " do include_context :dispute_created_withdrawn_and_lost_in_order_specs - + let(:obj) do StripeEvent.process_dispute(event_json_created) StripeEvent.process_dispute(event_json_funds_withdrawn) StripeEvent.process_dispute(event_json_lost) - StripeDispute.where('stripe_dispute_id = ?', json_lost['id']).first + StripeDispute.where("stripe_dispute_id = ?", json_lost["id"]).first end end - + describe "dispute.created-with-one-withdrawn -> dispute.funds_withdrawn -> dispute.closed, status = lost " do include_context :dispute_created_with_withdrawn_and_lost_in_order_specs - + let(:obj) do StripeEvent.process_dispute(event_json_created) StripeEvent.process_dispute(event_json_funds_withdrawn) StripeEvent.process_dispute(event_json_lost) - StripeDispute.where('stripe_dispute_id = ?', json_lost['id']).first + StripeDispute.where("stripe_dispute_id = ?", json_lost["id"]).first end end - + describe "dispute.closed, status = lost -> dispute.created -> dispute.funds_withdrawn" do include_context :dispute_lost_created_and_funds_withdrawn_at_same_time_spec - + let(:obj) do StripeEvent.process_dispute(event_json_lost) StripeEvent.process_dispute(event_json_created) StripeEvent.process_dispute(event_json_funds_withdrawn) - StripeDispute.where('stripe_dispute_id = ?', json_lost['id']).first - end + StripeDispute.where("stripe_dispute_id = ?", json_lost["id"]).first + end end - + describe "dispute.closed, status = won" do include_context :dispute_won_specs let(:obj) do StripeEvent.process_dispute(event_json) - StripeDispute.where('stripe_dispute_id = ?', json['id']).first + StripeDispute.where("stripe_dispute_id = ?", json["id"]).first end end describe "two disputes on the same transaction" do - describe 'partial1' do + describe "partial1" do include_context :dispute_with_two_partial_disputes_withdrawn_at_same_time_spec__partial1 let(:obj) do - StripeEvent.process_dispute(event_json_dispute_partial1); - StripeEvent.process_dispute(event_json_dispute_partial2); - StripeDispute.where(stripe_dispute_id: json_partial1['id']).first + StripeEvent.process_dispute(event_json_dispute_partial1) + StripeEvent.process_dispute(event_json_dispute_partial2) + StripeDispute.where(stripe_dispute_id: json_partial1["id"]).first end end - - describe 'partial2' do + + describe "partial2" do include_context :dispute_with_two_partial_disputes_withdrawn_at_same_time_spec__partial2 let(:obj) do - StripeEvent.process_dispute(event_json_dispute_partial1); - StripeEvent.process_dispute(event_json_dispute_partial2); - StripeDispute.where(stripe_dispute_id: json_partial2['id']).first + StripeEvent.process_dispute(event_json_dispute_partial1) + StripeEvent.process_dispute(event_json_dispute_partial2) + StripeDispute.where(stripe_dispute_id: json_partial2["id"]).first end end end @@ -130,7 +129,7 @@ include_context :legacy_dispute_specs let(:obj) do StripeEvent.process_dispute(event_json) - StripeDispute.where('stripe_dispute_id = ?', json['id']).first + StripeDispute.where("stripe_dispute_id = ?", json["id"]).first end end end diff --git a/spec/models/stripe_event_spec.rb b/spec/models/stripe_event_spec.rb index a831e8e9c..f4f39c5b1 100644 --- a/spec/models/stripe_event_spec.rb +++ b/spec/models/stripe_event_spec.rb @@ -1,66 +1,65 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe StripeEvent, :type => :model do +RSpec.describe StripeEvent, type: :model do around(:each) do |example| Timecop.freeze(Date.new(2021, 5, 4)) do - StripeMockHelper.mock do + StripeMockHelper.mock do example.run end end end - describe "stripe_account.updated" do + describe "stripe_account.updated" do let(:nonprofit_verification_process_status) do create(:nonprofit_verification_process_status, - stripe_account_id: 'acct_1G8Y94CcxDUSisy4', - started_at: DateTime.now - 1.minutes, - email_to_send_guid: fake_send_guid - ) + stripe_account_id: "acct_1G8Y94CcxDUSisy4", + started_at: DateTime.now - 1.minutes, + email_to_send_guid: fake_send_guid) end - let(:fake_send_guid) {'FAKE_GUID'} + let(:fake_send_guid) { "FAKE_GUID" } let(:event_object_for_pending) { create(:stripe_event, - event_id:"test_evt_1", - event_time: DateTime.now - 1.minutes, - object_id: 'acct_1G8Y94CcxDUSisy4') + event_id: "test_evt_1", + event_time: DateTime.now - 1.minutes, + object_id: "acct_1G8Y94CcxDUSisy4") } let(:later_event_object) { create(:stripe_event, - event_id:"test_evt_new", - event_time: DateTime.now + 1.minutes, - object_id: 'acct_1G8Y94CcxDUSisy4') + event_id: "test_evt_new", + event_time: DateTime.now + 1.minutes, + object_id: "acct_1G8Y94CcxDUSisy4") } let(:previous_event_object) { create(:stripe_event, - event_id:"test_evt_old", - event_time: DateTime.now - 1.minutes, - object_id: 'acct_1G8Y94CcxDUSisy4') + event_id: "test_evt_old", + event_time: DateTime.now - 1.minutes, + object_id: "acct_1G8Y94CcxDUSisy4") } - it 'skips processing already processed events' do + it "skips processing already processed events" do event_object_for_pending - StripeEvent.handle(StripeMockHelper.mock_webhook_event('account.updated.with-pending')) + StripeEvent.handle(StripeMockHelper.mock_webhook_event("account.updated.with-pending")) expect(StripeAccount.count).to eq 0 end - it 'skips processing weve already processed a newer event for object' do + it "skips processing weve already processed a newer event for object" do later_event_object - StripeEvent.handle(StripeMockHelper.mock_webhook_event('account.updated.with-pending')) + StripeEvent.handle(StripeMockHelper.mock_webhook_event("account.updated.with-pending")) expect(StripeAccount.count).to eq 0 end - describe 'new StripeAccount' do - describe 'handles unverified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-unverified')} + describe "new StripeAccount" do + describe "handles unverified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-unverified") } - let(:last_event) { StripeEvent.last} - let(:last_account) { StripeAccount.last} - - describe 'when in verification process' do + let(:last_event) { StripeEvent.last } + let(:last_account) { StripeAccount.last } + + describe "when in verification process" do before(:each) do nonprofit_verification_process_status previous_event_object @@ -70,52 +69,52 @@ StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to be :unverified end - it 'updates the NonprofitVerificationProcessStatus' do + it "updates the NonprofitVerificationProcessStatus" do nonprofit_verification_process_status.reload expect(nonprofit_verification_process_status.email_to_send_guid).to_not eq fake_send_guid end end - describe 'when not in verification process' do + describe "when not in verification process" do before(:each) do previous_event_object expect(StripeAccountMailer).to_not receive(:delay) StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to be :unverified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles temporarily_verified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-temporarily_verified')} + describe "handles temporarily_verified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-temporarily_verified") } + + let(:last_event) { StripeEvent.last } + let(:last_account) { StripeAccount.last } - let(:last_event) { StripeEvent.last} - let(:last_account) { StripeAccount.last} - - describe 'when in verification process' do + describe "when in verification process" do before(:each) do nonprofit_verification_process_status previous_event_object @@ -125,50 +124,50 @@ StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to be :temporarily_verified end - it 'updates the NonprofitVerificationProcessStatus' do - expect {nonprofit_verification_process_status.reload}.to raise_error ActiveRecord::RecordNotFound + it "updates the NonprofitVerificationProcessStatus" do + expect { nonprofit_verification_process_status.reload }.to raise_error ActiveRecord::RecordNotFound end end - describe 'when not in verification process' do + describe "when not in verification process" do before(:each) do previous_event_object expect(StripeAccountMailer).to_not receive(:delay) StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to eq :temporarily_verified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles verified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-verified')} - let(:last_event) { StripeEvent.last} - let(:last_account) { StripeAccount.last} - - describe 'when in verification process' do + describe "handles verified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-verified") } + let(:last_event) { StripeEvent.last } + let(:last_account) { StripeAccount.last } + + describe "when in verification process" do before(:each) do nonprofit_verification_process_status previous_event_object @@ -177,54 +176,53 @@ expect(StripeAccountMailer).to receive(:delay).and_return(sam) StripeEvent.handle(event_json) end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to be :verified end - it 'deleted the NonprofitVerificationProcessStatus' do - expect {nonprofit_verification_process_status.reload}.to raise_error ActiveRecord::RecordNotFound + it "deleted the NonprofitVerificationProcessStatus" do + expect { nonprofit_verification_process_status.reload }.to raise_error ActiveRecord::RecordNotFound end end - describe 'when not in verification process' do + describe "when not in verification process" do before(:each) do previous_event_object expect(StripeAccountMailer).to_not receive(:delay) StripeEvent.handle(event_json) end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to be :verified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end end + describe "old StripeAccount" do + describe "handles unverified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-unverified") } + let(:last_event) { StripeEvent.last } + let(:last_account) { create(:stripe_account, :with_unverified, stripe_account_id: "acct_1G8Y94CcxDUSisy4") } - describe 'old StripeAccount' do - describe 'handles unverified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-unverified')} - let(:last_event) { StripeEvent.last} - let(:last_account) { create(:stripe_account, :with_unverified, stripe_account_id:'acct_1G8Y94CcxDUSisy4')} - - describe 'when in verification process' do + describe "when in verification process" do before(:each) do nonprofit_verification_process_status last_account @@ -235,26 +233,25 @@ StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_2' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_2" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to be :unverified end - it 'updates the NonprofitVerificationProcessStatus' do - + it "updates the NonprofitVerificationProcessStatus" do nonprofit_verification_process_status.reload expect(nonprofit_verification_process_status.email_to_send_guid).to_not eq fake_send_guid end end - describe 'when not in verification process' do - let(:last_account) { create(:stripe_account, :with_unverified, stripe_account_id:'acct_1G8Y94CcxDUSisy4')} + describe "when not in verification process" do + let(:last_account) { create(:stripe_account, :with_unverified, stripe_account_id: "acct_1G8Y94CcxDUSisy4") } before(:each) do last_account previous_event_object @@ -262,30 +259,29 @@ StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_2' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_2" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to be :unverified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles from pending to unverified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-unverified')} - let(:last_event) { StripeEvent.last} - let(:last_account) { create(:stripe_account, :with_pending, stripe_account_id:'acct_1G8Y94CcxDUSisy4')} + describe "handles from pending to unverified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-unverified") } + let(:last_event) { StripeEvent.last } + let(:last_account) { create(:stripe_account, :with_pending, stripe_account_id: "acct_1G8Y94CcxDUSisy4") } - describe 'when in verification process' do - + describe "when in verification process" do before(:each) do nonprofit_verification_process_status last_account @@ -296,26 +292,25 @@ expect(last_account.verification_status).to eq :pending StripeEvent.handle(event_json) end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_2' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_2" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to be :unverified end - it 'updates the NonprofitVerificationProcessStatus' do - + it "updates the NonprofitVerificationProcessStatus" do nonprofit_verification_process_status.reload expect(nonprofit_verification_process_status.email_to_send_guid).to_not eq fake_send_guid end end - describe 'when not in verification process' do + describe "when not in verification process" do before(:each) do last_account previous_event_object @@ -323,31 +318,31 @@ expect(last_account.verification_status).to eq :pending StripeEvent.handle(event_json) end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_2' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_2" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to be :unverified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles temporarily_verified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-temporarily_verified')} + describe "handles temporarily_verified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-temporarily_verified") } - let(:last_event) { StripeEvent.last} - let(:last_account) { create(:stripe_account, stripe_account_id:'acct_1G8Y94CcxDUSisy4')} - - describe 'when in verification process' do + let(:last_event) { StripeEvent.last } + let(:last_account) { create(:stripe_account, stripe_account_id: "acct_1G8Y94CcxDUSisy4") } + + describe "when in verification process" do before(:each) do nonprofit_verification_process_status last_account @@ -359,22 +354,22 @@ last_account.reload end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to eq :temporarily_verified end - it 'updates the NonprofitVerificationProcessStatus' do - expect {nonprofit_verification_process_status.reload}.to raise_error ActiveRecord::RecordNotFound + it "updates the NonprofitVerificationProcessStatus" do + expect { nonprofit_verification_process_status.reload }.to raise_error ActiveRecord::RecordNotFound end end - - describe 'when not in verification process' do + + describe "when not in verification process" do before(:each) do previous_event_object last_account @@ -383,27 +378,27 @@ last_account.reload end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to eq :temporarily_verified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles verified' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-verified')} - let(:last_event) { StripeEvent.last} - let(:last_account) { create(:stripe_account, stripe_account_id:'acct_1G8Y94CcxDUSisy4', currently_due: ['something'])} - describe 'when in verification process' do + describe "handles verified" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-verified") } + let(:last_event) { StripeEvent.last } + let(:last_account) { create(:stripe_account, stripe_account_id: "acct_1G8Y94CcxDUSisy4", currently_due: ["something"]) } + describe "when in verification process" do before(:each) do nonprofit_verification_process_status last_account @@ -414,23 +409,23 @@ StripeEvent.handle(event_json) last_account.reload end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to be :verified end - it 'deleted the NonprofitVerificationProcessStatus' do - expect {nonprofit_verification_process_status.reload}.to raise_error ActiveRecord::RecordNotFound + it "deleted the NonprofitVerificationProcessStatus" do + expect { nonprofit_verification_process_status.reload }.to raise_error ActiveRecord::RecordNotFound end end - describe 'when not in verification process' do + describe "when not in verification process" do before(:each) do last_account previous_event_object @@ -438,28 +433,28 @@ StripeEvent.handle(event_json) last_account.reload end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do expect(last_account.verification_status).to eq :verified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles pending' do - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-pending')} - let(:last_event) { StripeEvent.last} - let(:last_account) { create(:stripe_account, stripe_account_id:'acct_1G8Y94CcxDUSisy4', currently_due: ['something'])} - describe 'when in verification process' do + describe "handles pending" do + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-pending") } + let(:last_event) { StripeEvent.last } + let(:last_account) { create(:stripe_account, stripe_account_id: "acct_1G8Y94CcxDUSisy4", currently_due: ["something"]) } + describe "when in verification process" do before(:each) do nonprofit_verification_process_status last_account @@ -468,59 +463,57 @@ expect(sam).to receive(:conditionally_send_not_completed) expect(StripeAccountMailer).to receive(:delay).and_return(sam) StripeEvent.handle(event_json) - end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to be :pending end - it 'updates the NonprofitVerificationProcessStatus' do - + it "updates the NonprofitVerificationProcessStatus" do nonprofit_verification_process_status.reload expect(nonprofit_verification_process_status.email_to_send_guid).to_not eq fake_send_guid end end - - describe 'when not in verification process' do + + describe "when not in verification process" do before(:each) do last_account previous_event_object expect(StripeAccountMailer).to_not receive(:delay) StripeEvent.handle(event_json) end - - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to be :pending end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end end - describe 'handles verified to unverified' do - let(:deadline) { Time.utc(2020, 2, 28, 22, 27, 35)} - let(:event_json) { StripeMockHelper.mock_webhook_event('account.updated.with-unverified-from-verified')} - let(:last_event) { StripeEvent.last} - let(:last_account) { create(:stripe_account, stripe_account_id:'acct_1G8Y94CcxDUSisy4')} + describe "handles verified to unverified" do + let(:deadline) { Time.utc(2020, 2, 28, 22, 27, 35) } + let(:event_json) { StripeMockHelper.mock_webhook_event("account.updated.with-unverified-from-verified") } + let(:last_event) { StripeEvent.last } + let(:last_account) { create(:stripe_account, stripe_account_id: "acct_1G8Y94CcxDUSisy4") } - describe 'when not in verification process' do + describe "when not in verification process" do before(:each) do last_account previous_event_object @@ -531,18 +524,18 @@ StripeEvent.handle(event_json) end - it 'saved the event' do - expect(last_event.event_id).to eq 'test_evt_1' - expect(last_event.object_id).to eq 'acct_1G8Y94CcxDUSisy4' + it "saved the event" do + expect(last_event.event_id).to eq "test_evt_1" + expect(last_event.object_id).to eq "acct_1G8Y94CcxDUSisy4" expect(last_event.event_time).to eq Time.now end - it 'saves StripeAccount' do + it "saves StripeAccount" do last_account.reload expect(last_account.verification_status).to eq :unverified end - it 'doesnt add a NonprofitVerificationProcessStatus' do + it "doesnt add a NonprofitVerificationProcessStatus" do expect(NonprofitVerificationProcessStatus.count).to eq 0 end end @@ -550,14 +543,14 @@ end end - describe 'charge.*' do + describe "charge.*" do describe "charge.succeeded" do include_context :charge_succeeded_specs let(:obj) do - # this is INCREDIBLY hacky - expect(Stripe::Charge).to receive(:retrieve).with(event_json['data']['object']['id']).and_return(Stripe::Util.convert_to_stripe_object(event_json['data']['object'])) + # this is INCREDIBLY hacky + expect(Stripe::Charge).to receive(:retrieve).with(event_json["data"]["object"]["id"]).and_return(Stripe::Util.convert_to_stripe_object(event_json["data"]["object"])) StripeEvent.process_charge(event_json) - StripeCharge.find_by_stripe_charge_id(json['id']) + StripeCharge.find_by_stripe_charge_id(json["id"]) end end end diff --git a/spec/models/stripe_transaction_charge_spec.rb b/spec/models/stripe_transaction_charge_spec.rb index d440ea9b3..a886a8ed1 100644 --- a/spec/models/stripe_transaction_charge_spec.rb +++ b/spec/models/stripe_transaction_charge_spec.rb @@ -2,18 +2,17 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe StripeTransactionCharge, type: :model do - it_behaves_like 'subtransaction paymentable', :stripechrg + it_behaves_like "subtransaction paymentable", :stripechrg - describe '#created' do - let(:payment) {instance_double('Payment')} + describe "#created" do + let(:payment) { instance_double("Payment") } let(:item) { item = described_class.new expect(item).to receive(:legacy_payment).and_return(payment) item - } it { expect(payment).to receive(:date) @@ -21,26 +20,23 @@ } end - describe '#stripe_id' do + describe "#stripe_id" do let(:payment) { - p = instance_double('Payment') + p = instance_double("Payment") expect(p).to receive(:charge).and_return(charge) p } - let(:charge) {instance_double('Charge')} + let(:charge) { instance_double("Charge") } - let(:item) { item = described_class.new expect(item).to receive(:legacy_payment).and_return(payment) item - } - + it { expect(charge).to receive(:stripe_charge_id) item.stripe_id } - end end diff --git a/spec/models/stripe_transaction_dispute_reversal_spec.rb b/spec/models/stripe_transaction_dispute_reversal_spec.rb index 069fed2bb..125f2912b 100644 --- a/spec/models/stripe_transaction_dispute_reversal_spec.rb +++ b/spec/models/stripe_transaction_dispute_reversal_spec.rb @@ -2,8 +2,8 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe StripeTransactionDisputeReversal, type: :model do - it_behaves_like 'subtransaction paymentable', :stripedisprvrs + it_behaves_like "subtransaction paymentable", :stripedisprvrs end diff --git a/spec/models/stripe_transaction_dispute_spec.rb b/spec/models/stripe_transaction_dispute_spec.rb index ba18c760d..c49815627 100644 --- a/spec/models/stripe_transaction_dispute_spec.rb +++ b/spec/models/stripe_transaction_dispute_spec.rb @@ -2,18 +2,17 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe StripeTransactionDispute, type: :model do - it_behaves_like 'subtransaction paymentable', :stripedisp - - describe '#created' do - let(:payment) {instance_double('Payment')} + it_behaves_like "subtransaction paymentable", :stripedisp + + describe "#created" do + let(:payment) { instance_double("Payment") } let(:item) { item = described_class.new expect(item).to receive(:legacy_payment).and_return(payment) item - } it { expect(payment).to receive(:date) diff --git a/spec/models/stripe_transaction_refund_spec.rb b/spec/models/stripe_transaction_refund_spec.rb index c20ba5230..e27cfbac3 100644 --- a/spec/models/stripe_transaction_refund_spec.rb +++ b/spec/models/stripe_transaction_refund_spec.rb @@ -2,8 +2,8 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe StripeTransactionRefund, type: :model do - it_behaves_like 'subtransaction paymentable', :striperef + it_behaves_like "subtransaction paymentable", :striperef end diff --git a/spec/models/stripe_transaction_spec.rb b/spec/models/stripe_transaction_spec.rb index 23c42b74e..eb3826aa8 100644 --- a/spec/models/stripe_transaction_spec.rb +++ b/spec/models/stripe_transaction_spec.rb @@ -2,12 +2,12 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe StripeTransaction, type: :model do - it_behaves_like 'subtransactable', :stripetrx, :stripe_transaction_for_testing_payment_extensions + it_behaves_like "subtransactable", :stripetrx, :stripe_transaction_for_testing_payment_extensions - it { - is_expected.to delegate_method(:net_amount).to(:subtransaction_payments) - } + it { + is_expected.to delegate_method(:net_amount).to(:subtransaction_payments) + } end diff --git a/spec/models/subtransaction_payment_spec.rb b/spec/models/subtransaction_payment_spec.rb index 581063cb2..4dff87467 100644 --- a/spec/models/subtransaction_payment_spec.rb +++ b/spec/models/subtransaction_payment_spec.rb @@ -2,21 +2,18 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe SubtransactionPayment, type: :model do - - it { is_expected.to(belong_to(:subtransaction).inverse_of(:subtransaction_payments)) } it { is_expected.to(have_one(:trx) - .class_name('Transaction') - .with_foreign_key('transaction_id') - .through(:subtransaction) - ) + .class_name("Transaction") + .with_foreign_key("transaction_id") + .through(:subtransaction)) } it { @@ -28,7 +25,7 @@ } it { - is_expected.to(belong_to(:legacy_payment).class_name('Payment').required(true)) + is_expected.to(belong_to(:legacy_payment).class_name("Payment").required(true)) } it { @@ -58,5 +55,4 @@ it { is_expected.to validate_presence_of(:paymentable) } - end diff --git a/spec/models/subtransaction_spec.rb b/spec/models/subtransaction_spec.rb index 2f9ecd81d..1a34f27cf 100644 --- a/spec/models/subtransaction_spec.rb +++ b/spec/models/subtransaction_spec.rb @@ -2,18 +2,16 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe Subtransaction, type: :model do - - it_behaves_like 'a class with payments extension', :subtransaction_payments, :subtransaction_for_testing_payment_extensions + it_behaves_like "a class with payments extension", :subtransaction_payments, :subtransaction_for_testing_payment_extensions it { is_expected.to(belong_to(:trx) - .class_name('Transaction') - .with_foreign_key('transaction_id') - .inverse_of(:subtransaction) - ) + .class_name("Transaction") + .with_foreign_key("transaction_id") + .inverse_of(:subtransaction)) } it { @@ -39,5 +37,4 @@ it { is_expected.to validate_presence_of :subtransactable } - end diff --git a/spec/models/supporter_address_spec.rb b/spec/models/supporter_address_spec.rb index fbe65527b..d0c80752c 100644 --- a/spec/models/supporter_address_spec.rb +++ b/spec/models/supporter_address_spec.rb @@ -1,24 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe SupporterAddress, type: :model do - it { is_expected.to belong_to(:supporter).required(true).inverse_of(:addresses)} + it { is_expected.to belong_to(:supporter).required(true).inverse_of(:addresses) } - describe '#primary?' do - let(:supporter) { create(:supporter)} + describe "#primary?" do + let(:supporter) { create(:supporter) } let(:non_primary_address) { create(:supporter_address, supporter: supporter) } - let(:primary_address) { - pa = create(:supporter_address, supporter: supporter) + let(:primary_address) { + pa = create(:supporter_address, supporter: supporter) supporter.primary_address = pa supporter.save! pa } - it 'is true when supporter has sets as primary' do + it "is true when supporter has sets as primary" do expect(primary_address).to be_primary end - it 'is false when supporter hasnt sets as primary' do + it "is false when supporter hasnt sets as primary" do expect(non_primary_address).to_not be_primary end end diff --git a/spec/models/supporter_spec.rb b/spec/models/supporter_spec.rb index 05df125dc..470a00fa7 100644 --- a/spec/models/supporter_spec.rb +++ b/spec/models/supporter_spec.rb @@ -1,34 +1,32 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - +require "rails_helper" RSpec.describe Supporter, type: :model do - it_behaves_like 'an houidable entity', :supp - it_behaves_like 'a model with a calculated first and last name' + it_behaves_like "an houidable entity", :supp + it_behaves_like "a model with a calculated first and last name" - it { is_expected.to have_many(:addresses).class_name("SupporterAddress")} - it { is_expected.to belong_to(:primary_address).class_name("SupporterAddress")} + it { is_expected.to have_many(:addresses).class_name("SupporterAddress") } + it { is_expected.to belong_to(:primary_address).class_name("SupporterAddress") } it { is_expected.to have_many(:object_events) } - - describe 'Supporter::Tags' do - it { is_expected.to have_many(:tag_joins)} - it { is_expected.to have_many(:tag_masters).through(:tag_joins)} - it { is_expected.to have_many(:undeleted_tag_masters).through(:tag_joins).class_name("TagMaster").source('tag_master')} - - describe '.undeleted_tag_masters' do - it 'only contains undeleted tags masters' do + + describe "Supporter::Tags" do + it { is_expected.to have_many(:tag_joins) } + it { is_expected.to have_many(:tag_masters).through(:tag_joins) } + it { is_expected.to have_many(:undeleted_tag_masters).through(:tag_joins).class_name("TagMaster").source("tag_master") } + + describe ".undeleted_tag_masters" do + it "only contains undeleted tags masters" do nonprofit = create(:nonprofit_base) undeleted_tag_master = create(:tag_master_base, nonprofit: nonprofit) deleted_tag_master = create(:tag_master_base, nonprofit: nonprofit, deleted: true) supporter = create(:supporter_base, nonprofit: nonprofit, tag_joins: [build(:tag_join_base, tag_master: undeleted_tag_master), build(:tag_join_base, tag_master: deleted_tag_master)]) expect(supporter.undeleted_tag_masters).to contain_exactly(undeleted_tag_master) - end end end - describe 'Supporter::EmailLists' do + describe "Supporter::EmailLists" do it { is_expected.to have_many(:email_lists).through(:tag_masters) } it { is_expected.to have_many(:active_email_lists).through(:undeleted_tag_masters).source("email_list") } @@ -45,15 +43,14 @@ def prepare ActiveJob::Base.queue_adapter = :test # this is to clear any jobs that might have been created these objects ret end - describe '.active_email_lists' do - it 'only contains an active email list tags masters' do + describe ".active_email_lists" do + it "only contains an active email list tags masters" do ret = prepare expect(ret.supporter.active_email_lists).to contain_exactly(ret.undeleted_tag_master.email_list) - end - describe '.update_member_on_all_lists' do - it 'updates the correct lists' do + describe ".update_member_on_all_lists" do + it "updates the correct lists" do ret = prepare supporter = ret.supporter @@ -66,36 +63,36 @@ def prepare end end - describe 'update email lists on supporter save' do - it 'when name changed' do + describe "update email lists on supporter save" do + it "when name changed" do ret = prepare expect(ret.supporter).to receive(:update_member_on_all_lists) ret.supporter.update(name: "Another name") end - it 'when email changed' do + it "when email changed" do ret = prepare expect(ret.supporter).to receive(:update_member_on_all_lists) ret.supporter.update(email: "another@email.address") end - it 'but not when phone number changes' do + it "but not when phone number changes" do ret = prepare expect(ret.supporter).to_not receive(:update_member_on_all_lists) ret.supporter.update(phone: 920418918) end end - context 'after_save' do - describe '.update_member_on_all_lists' do - it 'updates the correct lists on name change' do + context "after_save" do + describe ".update_member_on_all_lists" do + it "updates the correct lists on name change" do ret = prepare ret.supporter.update(name: "Another name") expect(MailchimpSignupJob).to have_been_enqueued.with(ret.supporter, ret.undeleted_tag_master.email_list) end - it 'updates nothing if something other than name and email change' do + it "updates nothing if something other than name and email change" do ret = prepare expect(MailchimpSignupJob).to_not have_been_enqueued ret.supporter.update(phone: "9305268998") @@ -106,8 +103,6 @@ def prepare end end - - describe "#calculated_first_name" do it "has nil name" do supporter = build_stubbed(:supporter, name: nil) @@ -162,65 +157,60 @@ def prepare end end - describe "#cleanup_name" do - it 'keeps name when no first and last name' do - s = Supporter.new(name: 'Penelope') + describe "#cleanup_name" do + it "keeps name when no first and last name" do + s = Supporter.new(name: "Penelope") s.valid? expect(s.name).to eq "Penelope" end - - it 'keeps copies first to name' do - s = Supporter.new(name: 'Penelope', first_name: 'Eric') + it "keeps copies first to name" do + s = Supporter.new(name: "Penelope", first_name: "Eric") s.valid? expect(s.name).to eq "Eric" end - it 'copies last to name' do - - s = Supporter.new(name: 'Penelope', first_name: 'Eric', last_name: 'Schultz') + it "copies last to name" do + s = Supporter.new(name: "Penelope", first_name: "Eric", last_name: "Schultz") s.valid? expect(s.name).to eq "Eric Schultz" end - - it 'copies first and last to name' do - s = Supporter.new(first_name: 'Eric', last_name: 'Schultz') + + it "copies first and last to name" do + s = Supporter.new(first_name: "Eric", last_name: "Schultz") s.valid? expect(s.name).to eq "Eric Schultz" end - end - - describe "#cleanup_address" do - it 'keeps address when no address_line2' do - s = Supporter.new(address: '123 Main Street') + describe "#cleanup_address" do + it "keeps address when no address_line2" do + s = Supporter.new(address: "123 Main Street") s.valid? - expect(s.address).to eq '123 Main Street' + expect(s.address).to eq "123 Main Street" end - it 'copies no address_line2 when address is empty when' do - s = Supporter.new() + it "copies no address_line2 when address is empty when" do + s = Supporter.new s.valid? expect(s.address).to be_blank end - it 'combines address and address_line2 when both there' do - s = Supporter.new(address:'123 Main Street', address_line2: 'Suite 101' ) + it "combines address and address_line2 when both there" do + s = Supporter.new(address: "123 Main Street", address_line2: "Suite 101") s.valid? - expect(s.address).to eq '123 Main Street Suite 101' + expect(s.address).to eq "123 Main Street Suite 101" end - it 'replaces blank attributes with nil' do - s = Supporter.new(address: '') + it "replaces blank attributes with nil" do + s = Supporter.new(address: "") s.valid? expect(s.address).to be_nil end end - - context 'after_save' do - describe 'update_primary_address' do + context "after_save" do + describe "update_primary_address" do def have_one_address have_attributes(addresses: have_attributes(count: 1)) end @@ -238,46 +228,41 @@ def empty_address_attributes attributes_for(:supporter_with_fv_poverty, :with_empty_address).slice(:address, :state_code, :country, :zip_code, :city) end - context 'when primary_address is originally nil' do - context 'and address is being created' do - + context "when primary_address is originally nil" do + context "and address is being created" do def create_supporter_and_update_supporter_address supporter = create(:supporter_with_fv_poverty) supporter.update_attributes(custom_address_attributes) supporter end - - it { + + it { supporter = create_supporter_and_update_supporter_address expect(supporter).to have_one_address } - it { + it { supporter = create_supporter_and_update_supporter_address expect(supporter).to have_saved_primary_address } - + it { - supporter = create_supporter_and_update_supporter_address expect(supporter.primary_address).to have_attributes(custom_address_attributes) - } - - - context 'and the address is being updated to nil attributes' do + context "and the address is being updated to nil attributes" do def empty_the_supporter_address(supporter) supporter.update(empty_address_attributes) end - it 'removes the primary address from the supporter' do + it "removes the primary address from the supporter" do supporter = create_supporter_and_update_supporter_address empty_the_supporter_address(supporter) expect(supporter.primary_address).to be_nil end - it 'deletes the empty primary address from the database' do + it "deletes the empty primary address from the database" do supporter = create_supporter_and_update_supporter_address primary_address_id = supporter.primary_address.id empty_the_supporter_address(supporter) @@ -286,33 +271,32 @@ def empty_the_supporter_address(supporter) end end - context 'and the supporter being created has empty address fields' do - it 'does not create a primary address' do + context "and the supporter being created has empty address fields" do + it "does not create a primary address" do supporter = create(:supporter_with_fv_poverty, :with_blank_address) expect(supporter.primary_address).to be_nil end end end - context 'when primary_address originally exists' do - + context "when primary_address originally exists" do def create_and_update_supporter_with_already_created_address supporter = create(:supporter_with_fv_poverty, :with_primary_address) supporter.update(custom_address_attributes) supporter end - - it { + + it { supporter = create_and_update_supporter_with_already_created_address expect(supporter).to have_one_address } - it { + it { supporter = create_and_update_supporter_with_already_created_address expect(supporter).to have_saved_primary_address } - - it 'has new primary address' do + + it "has new primary address" do supporter = create_and_update_supporter_with_already_created_address expect(supporter.primary_address).to have_attributes(custom_address_attributes) end @@ -321,13 +305,13 @@ def create_and_update_supporter_with_already_created_address end describe "#payments#during_np_year" do - let(:nonprofit) { create(:nonprofit_base)} - let(:supporter) { create(:supporter_base, nonprofit:nonprofit)} - let(:payment1) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 1.second)} - let(:payment2) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 7.hours)} # this is after midnight at Central Time - let(:payment3){ create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.end_of_year + 1.second)} # this is before midnight at Central Time but after UTC + let(:nonprofit) { create(:nonprofit_base) } + let(:supporter) { create(:supporter_base, nonprofit: nonprofit) } + let(:payment1) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 1.second) } + let(:payment2) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.beginning_of_year + 7.hours) } # this is after midnight at Central Time + let(:payment3) { create(:payment_base, :with_offline_payment, supporter: supporter, nonprofit: nonprofit, date: Time.new.utc.end_of_year + 1.second) } # this is before midnight at Central Time but after UTC - before(:each) do + before(:each) do payment1 payment2 payment3 @@ -343,5 +327,4 @@ def create_and_update_supporter_with_already_created_address expect(supporter.payments.during_np_year(Time.new.utc.year)).to contain_exactly(payment2, payment3) end end - end diff --git a/spec/models/tag_join/modification_spec.rb b/spec/models/tag_join/modification_spec.rb index f961da52b..def9e4f4a 100644 --- a/spec/models/tag_join/modification_spec.rb +++ b/spec/models/tag_join/modification_spec.rb @@ -1,9 +1,9 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe TagJoin::Modification, :type => :model do +RSpec.describe TagJoin::Modification, type: :model do describe "#initialize" do - it 'works when nothing needs to be casted' do + it "works when nothing needs to be casted" do tag_master = create(:tag_master_base) expect(TagJoin::Modification.new(tag_master_id: tag_master.id, selected: false)).to have_attributes( tag_master_id: tag_master.id, @@ -12,13 +12,13 @@ ) end - it 'works when it receives a ActionController::Parameters that is permitted' do + it "works when it receives a ActionController::Parameters that is permitted" do tag_master = create(:tag_master_base) params = ActionController::Parameters.new(tag_master_id: tag_master.id, selected: false).permit(:tag_master_id, :selected) expect { TagJoin::Modification.new(params) }.to_not raise_error end - it 'works when everything needs to be casted' do + it "works when everything needs to be casted" do tag_master = create(:tag_master_base) expect(TagJoin::Modification.new(tag_master_id: tag_master.id.to_s, selected: "false")).to have_attributes( tag_master_id: tag_master.id, @@ -27,7 +27,4 @@ ) end end - - - -end \ No newline at end of file +end diff --git a/spec/models/tag_join/modifications_spec.rb b/spec/models/tag_join/modifications_spec.rb index 3f9b44b7c..6c1ff621e 100644 --- a/spec/models/tag_join/modifications_spec.rb +++ b/spec/models/tag_join/modifications_spec.rb @@ -1,44 +1,46 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe TagJoin::Modifications, :type => :model do - it '#initialize' do +RSpec.describe TagJoin::Modifications, type: :model do + it "#initialize" do nonprofit = create(:nonprofit_base) - tag_joins = [create(:tag_join_base, supporter:create(:supporter_base, nonprofit: nonprofit), tag_master: create(:tag_master_base, nonprofit:nonprofit))] + tag_joins = [create(:tag_join_base, supporter: create(:supporter_base, nonprofit: nonprofit), tag_master: create(:tag_master_base, nonprofit: nonprofit))] - expect(TagJoin::Modifications.new([{tag_master_id: tag_joins.first.tag_master_id, selected: 'true'}])).to match( - an_instance_of(TagJoin::Modifications).and containing_exactly( - an_instance_of(TagJoin::Modification).and have_attributes(tag_master_id: tag_joins.first.tag_master_id, selected: true, tag_master: tag_joins.first.tag_master) - )) + expect(TagJoin::Modifications.new([{tag_master_id: tag_joins.first.tag_master_id, selected: "true"}])).to match( + an_instance_of(TagJoin::Modifications).and(containing_exactly( + an_instance_of(TagJoin::Modification).and(have_attributes(tag_master_id: tag_joins.first.tag_master_id, selected: true, tag_master: tag_joins.first.tag_master)) + )) + ) end - it '#selected' do - expect(TagJoin::Modifications.new([{tag_master_id: 1, selected: true}, {tag_master_id: 2, selected:false} ]).selected).to match( - an_instance_of(TagJoin::Modifications).and containing_exactly( - an_instance_of(TagJoin::Modification).and have_attributes(tag_master_id: 1, selected: true) - )) + it "#selected" do + expect(TagJoin::Modifications.new([{tag_master_id: 1, selected: true}, {tag_master_id: 2, selected: false}]).selected).to match( + an_instance_of(TagJoin::Modifications).and(containing_exactly( + an_instance_of(TagJoin::Modification).and(have_attributes(tag_master_id: 1, selected: true)) + )) + ) end - it '#unselected' do - expect(TagJoin::Modifications.new([{tag_master_id: 1, selected: true}, {tag_master_id: 2, selected:false} ]).unselected).to match( - an_instance_of(TagJoin::Modifications).and containing_exactly( - an_instance_of(TagJoin::Modification).and have_attributes(tag_master_id: 2, selected: false) - )) + it "#unselected" do + expect(TagJoin::Modifications.new([{tag_master_id: 1, selected: true}, {tag_master_id: 2, selected: false}]).unselected).to match( + an_instance_of(TagJoin::Modifications).and(containing_exactly( + an_instance_of(TagJoin::Modification).and(have_attributes(tag_master_id: 2, selected: false)) + )) + ) end - - describe '#for_given_tags' do - it 'gets correct tags when given integers' do - expect(TagJoin::Modifications.new([{tag_master_id: 1, selected: true}, {tag_master_id: 2, selected:false} ]).for_given_tags([4, 1])).to match(a_collection_containing_exactly( - an_instance_of(TagJoin::Modification).and have_attributes(tag_master_id: 1, selected: true) + describe "#for_given_tags" do + it "gets correct tags when given integers" do + expect(TagJoin::Modifications.new([{tag_master_id: 1, selected: true}, {tag_master_id: 2, selected: false}]).for_given_tags([4, 1])).to match(a_collection_containing_exactly( + an_instance_of(TagJoin::Modification).and(have_attributes(tag_master_id: 1, selected: true)) )) end - it 'gets correct tags when given TagMaster' do + it "gets correct tags when given TagMaster" do tag_master = create(:tag_master_base) - expect(TagJoin::Modifications.new([{tag_master_id: tag_master.id, selected: true}, {tag_master_id: tag_master.id + 1, selected:false} ]).for_given_tags([tag_master])).to match(a_collection_containing_exactly( - an_instance_of(TagJoin::Modification).and have_attributes(tag_master_id: tag_master.id, selected: true) + expect(TagJoin::Modifications.new([{tag_master_id: tag_master.id, selected: true}, {tag_master_id: tag_master.id + 1, selected: false}]).for_given_tags([tag_master])).to match(a_collection_containing_exactly( + an_instance_of(TagJoin::Modification).and(have_attributes(tag_master_id: tag_master.id, selected: true)) )) end end -end \ No newline at end of file +end diff --git a/spec/models/ticket_purchase_spec.rb b/spec/models/ticket_purchase_spec.rb index 43f356642..7ba408c02 100644 --- a/spec/models/ticket_purchase_spec.rb +++ b/spec/models/ticket_purchase_spec.rb @@ -2,10 +2,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe TicketPurchase, type: :model do - it_behaves_like 'trx assignable', :tktpur + it_behaves_like "trx assignable", :tktpur it { is_expected.to have_many(:tickets) diff --git a/spec/models/ticket_spec.rb b/spec/models/ticket_spec.rb index 0a57172cc..f086fef65 100644 --- a/spec/models/ticket_spec.rb +++ b/spec/models/ticket_spec.rb @@ -1,40 +1,38 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" RSpec.describe Ticket, type: :model do - it { is_expected.to belong_to(:ticket_purchase) } - let(:payment1) { force_create(:payment)} - let(:payment2) { force_create(:payment)} - let(:ticket1) { force_create(:ticket, payment: payment1)} - let(:ticket2) { force_create(:ticket, payment: payment1)} - let(:ticket3) { force_create(:ticket, payment: payment1)} - let(:ticket4) { force_create(:ticket, payment: payment2)} + let(:payment1) { force_create(:payment) } + let(:payment2) { force_create(:payment) } + let(:ticket1) { force_create(:ticket, payment: payment1) } + let(:ticket2) { force_create(:ticket, payment: payment1) } + let(:ticket3) { force_create(:ticket, payment: payment1) } + let(:ticket4) { force_create(:ticket, payment: payment2) } before(:each) do - ticket1 - ticket2 - ticket3 - ticket4 + ticket1 + ticket2 + ticket3 + ticket4 end - it 'has ticket1 getting ticket2 and ticket3 for related_tickets' do + it "has ticket1 getting ticket2 and ticket3 for related_tickets" do expect(ticket1.related_tickets).to contain_exactly(ticket2, ticket3) end - it 'has ticket2 getting ticket1 and ticket3 for related_tickets' do + it "has ticket2 getting ticket1 and ticket3 for related_tickets" do expect(ticket2.related_tickets).to contain_exactly(ticket1, ticket3) end - - it 'has ticket3 getting ticket1 and ticket2 for related_tickets' do + it "has ticket3 getting ticket1 and ticket2 for related_tickets" do expect(ticket3.related_tickets).to contain_exactly(ticket1, ticket2) end - it 'has ticket4 getting no related tickets' do + it "has ticket4 getting no related tickets" do expect(ticket4.related_tickets).to be_empty end end diff --git a/spec/models/transaction_assignment_spec.rb b/spec/models/transaction_assignment_spec.rb index 88794de15..892619e20 100644 --- a/spec/models/transaction_assignment_spec.rb +++ b/spec/models/transaction_assignment_spec.rb @@ -2,16 +2,14 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe TransactionAssignment, type: :model do - it { is_expected.to(belong_to(:trx) - .class_name('Transaction') - .with_foreign_key('transaction_id').required(true) - .inverse_of(:transaction_assignments) - ) + .class_name("Transaction") + .with_foreign_key("transaction_id").required(true) + .inverse_of(:transaction_assignments)) } it { @@ -29,5 +27,4 @@ it { is_expected.to validate_presence_of(:assignable) } - end diff --git a/spec/models/transaction_spec.rb b/spec/models/transaction_spec.rb index 166545caa..8c3f92fda 100644 --- a/spec/models/transaction_spec.rb +++ b/spec/models/transaction_spec.rb @@ -2,15 +2,14 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe Transaction, type: :model do - it_behaves_like 'an houidable entity', :trx + it_behaves_like "an houidable entity", :trx - it_behaves_like 'a class with payments extension', :payments, :transaction_for_testing_payment_extensions + it_behaves_like "a class with payments extension", :payments, :transaction_for_testing_payment_extensions - it_behaves_like 'an object with as_money attributes', :amount - + it_behaves_like "an object with as_money attributes", :amount it { is_expected.to(belong_to(:supporter).required(true)) @@ -19,29 +18,27 @@ it { is_expected.to(have_one(:nonprofit).through(:supporter)) } - + it { is_expected.to(have_one(:subtransaction).inverse_of(:trx)) } it { - is_expected.to(have_many(:transaction_assignments).inverse_of('trx')) + is_expected.to(have_many(:transaction_assignments).inverse_of("trx")) } it { is_expected.to(have_many(:donations) .through(:transaction_assignments) .source(:assignable) - .class_name("ModernDonation") - ) + .class_name("ModernDonation")) } it { is_expected.to(have_many(:ticket_purchases) .through(:transaction_assignments) .source(:assignable) - .class_name("TicketPurchase") - ) + .class_name("TicketPurchase")) } it { @@ -49,11 +46,11 @@ } it { - is_expected.to(have_many(:payments).through(:subtransaction).source(:subtransaction_payments).class_name('SubtransactionPayment')) + is_expected.to(have_many(:payments).through(:subtransaction).source(:subtransaction_payments).class_name("SubtransactionPayment")) } - describe 'houid is created' do - subject { Transaction.create(supporter:create(:supporter))} - it {is_expected.to have_attributes(houid: match_houid('trx'))} + describe "houid is created" do + subject { Transaction.create(supporter: create(:supporter)) } + it { is_expected.to have_attributes(houid: match_houid("trx")) } end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8b3316cd0..067b3233c 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,95 +1,91 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -RSpec.describe User, :type => :model do - it_behaves_like 'a model with a calculated first and last name' +RSpec.describe User, type: :model do + it_behaves_like "a model with a calculated first and last name" - it {is_expected.to have_db_column(:locked_at).of_type(:datetime)} - it {is_expected.to have_db_column(:unlock_token).of_type(:string)} - it {is_expected.to have_db_column(:failed_attempts).of_type(:integer).with_options(default:0, null:false)} + it { is_expected.to have_db_column(:locked_at).of_type(:datetime) } + it { is_expected.to have_db_column(:unlock_token).of_type(:string) } + it { is_expected.to have_db_column(:failed_attempts).of_type(:integer).with_options(default: 0, null: false) } - it 'locks correctly after 10 attempts' do + it "locks correctly after 10 attempts" do user = create(:user) user.confirm - - 10.times { user.valid_for_authentication?{ false } } + + 10.times { user.valid_for_authentication? { false } } assert user.reload.access_locked? end - - describe '.nonprofit_personnel' do - let!(:user) {create(:user)} - let!(:user_as_nonprofit_admin) {create(:user_as_nonprofit_admin)} - let!(:user_as_nonprofit_associate) {create(:user_as_nonprofit_associate)} - it 'returns a user that is a nonprofit_admin' do - expect(User.nonprofit_personnel).to include(user_as_nonprofit_admin) - end + describe ".nonprofit_personnel" do + let!(:user) { create(:user) } + let!(:user_as_nonprofit_admin) { create(:user_as_nonprofit_admin) } + let!(:user_as_nonprofit_associate) { create(:user_as_nonprofit_associate) } + it "returns a user that is a nonprofit_admin" do + expect(User.nonprofit_personnel).to include(user_as_nonprofit_admin) + end - it 'returns a user that is a nonprofit_associate' do + it "returns a user that is a nonprofit_associate" do expect(User.nonprofit_personnel).to include(user_as_nonprofit_associate) - end + end - it 'DOES NOT return a user that is a nonprofit_admin OR a nonprofit_associate' do + it "DOES NOT return a user that is a nonprofit_admin OR a nonprofit_associate" do expect(User.nonprofit_personnel).to_not include(user) - end - - end - - describe '.send_reset_password_instructions' do - - context 'with a valid email address' do + end + end - context 'when the user hasn\'t requested a reset password token before' do - it 'returns a User' do - create(:user, email: 'evil_hacker@netflix.io') - expect(User.send_reset_password_instructions(attributes={email: 'evil_hacker@netflix.io'})).to be_a User + describe ".send_reset_password_instructions" do + context "with a valid email address" do + context "when the user hasn't requested a reset password token before" do + it "returns a User" do + create(:user, email: "evil_hacker@netflix.io") + expect(User.send_reset_password_instructions({email: "evil_hacker@netflix.io"})).to be_a User end - it 'returns the correct user' do - user = create(:user, email: 'sneaky_scammer@fb.net') - expect(User.send_reset_password_instructions(attributes={email: 'sneaky_scammer@fb.net'})).to eq(user) + it "returns the correct user" do + user = create(:user, email: "sneaky_scammer@fb.net") + expect(User.send_reset_password_instructions({email: "sneaky_scammer@fb.net"})).to eq(user) end - it 'returns an object with no errors' do - create(:user, email: 'gone_phishing@twtr.gov') - expect(User.send_reset_password_instructions(attributes={email: 'gone_phishing@twtr.gov'}).errors.messages).to eq({}) + it "returns an object with no errors" do + create(:user, email: "gone_phishing@twtr.gov") + expect(User.send_reset_password_instructions({email: "gone_phishing@twtr.gov"}).errors.messages).to eq({}) end end - context 'when a user has requested a reset password token recently (< 5 min ago)' do - it 'returns the correct user' do - user = create(:user, email: 'fraud_fool@insta.org') - User.send_reset_password_instructions(attributes={email: 'fraud_fool@insta.org'}) - expect(User.send_reset_password_instructions(attributes={email: 'fraud_fool@insta.org'})).to eq(user) + context "when a user has requested a reset password token recently (< 5 min ago)" do + it "returns the correct user" do + user = create(:user, email: "fraud_fool@insta.org") + User.send_reset_password_instructions({email: "fraud_fool@insta.org"}) + expect(User.send_reset_password_instructions({email: "fraud_fool@insta.org"})).to eq(user) end it 'adds "can\'t reset password because a request was just sent" error to returned user' do - create(:user, email: 'perilous_programmer@snap.com') - User.send_reset_password_instructions(attributes={email: 'perilous_programmer@snap.com'}) + create(:user, email: "perilous_programmer@snap.com") + User.send_reset_password_instructions({email: "perilous_programmer@snap.com"}) expect( - User.send_reset_password_instructions(attributes={email: 'perilous_programmer@snap.com'}).errors.messages[:base] + User.send_reset_password_instructions({email: "perilous_programmer@snap.com"}).errors.messages[:base] ).to eq(["can't reset password because a request was just sent"]) end end end - context 'with an invalid email address' do - it 'returns a User' do + context "with an invalid email address" do + it "returns a User" do expect( - User.send_reset_password_instructions(attributes={email: 'unknown_goose@domain.net'}) + User.send_reset_password_instructions({email: "unknown_goose@domain.net"}) ).to be_a User end - it 'returns a blank User' do + it "returns a blank User" do expect( - User.send_reset_password_instructions(attributes={email: 'unknown_panda@domain.net'}).id + User.send_reset_password_instructions({email: "unknown_panda@domain.net"}).id ).to be_nil end it 'adds "not found" errors to email' do expect( - User.send_reset_password_instructions(attributes={email: 'unknown_lizard@domain.net'}).errors.messages[:email] + User.send_reset_password_instructions({email: "unknown_lizard@domain.net"}).errors.messages[:email] ).to eq(["not found"]) end end diff --git a/spec/models/widget_description_spec.rb b/spec/models/widget_description_spec.rb index 7ab8ae8df..7c1633556 100644 --- a/spec/models/widget_description_spec.rb +++ b/spec/models/widget_description_spec.rb @@ -1,45 +1,40 @@ -require 'rails_helper' +require "rails_helper" RSpec.describe WidgetDescription, type: :model do - it_behaves_like 'an houidable entity', :wdgtdesc + it_behaves_like "an houidable entity", :wdgtdesc - it {is_expected.to have_many :campaigns} - - describe '#custom_amounts' do - it { is_expected.to allow_values([ 31000]).for(:custom_amounts) } + it { is_expected.to have_many :campaigns } + describe "#custom_amounts" do + it { is_expected.to allow_values([31000]).for(:custom_amounts) } it { is_expected.to allow_values(nil).for(:custom_amounts) } + it { is_expected.to allow_values([31000, {amount: 20000, postfix: true}]).for(:custom_amounts) } - it { is_expected.to allow_values([ 31000, {amount: 20000, postfix:true}]).for(:custom_amounts) } - - it { is_expected.to allow_values([ 31000, {amount: 20000}]).for(:custom_amounts) } + it { is_expected.to allow_values([31000, {amount: 20000}]).for(:custom_amounts) } - it { is_expected.to_not allow_values({}).for(:custom_amounts)} + it { is_expected.to_not allow_values({}).for(:custom_amounts) } it { is_expected.to_not allow_values([]).for(:custom_amounts) } - it { is_expected.to_not allow_values([ 31000, {postfix: true}]).for(:custom_amounts) } + it { is_expected.to_not allow_values([31000, {postfix: true}]).for(:custom_amounts) } - it { is_expected.to_not allow_values([ 310.00]).for(:custom_amounts) } + it { is_expected.to_not allow_values([310.00]).for(:custom_amounts) } - it { is_expected.to_not allow_values(["a string"]).for(:custom_amounts)} + it { is_expected.to_not allow_values(["a string"]).for(:custom_amounts) } end - - describe '#custom_recurring_donation_phrase' do - - it {is_expected.to allow_value(nil).for(:custom_recurring_donation_phrase) } - it {is_expected.to allow_value("Custom recurring donation phrase").for(:custom_recurring_donation_phrase)} + describe "#custom_recurring_donation_phrase" do + it { is_expected.to allow_value(nil).for(:custom_recurring_donation_phrase) } + it { is_expected.to allow_value("Custom recurring donation phrase").for(:custom_recurring_donation_phrase) } end - - describe '#postfix_element' do + describe "#postfix_element" do it { is_expected.to allow_value(nil).for(:postfix_element) } - it { is_expected.to allow_value({type: 'info', html_content: "We are going to
Something"}).for(:postfix_element)} + it { is_expected.to allow_value({type: "info", html_content: "We are going to
Something"}).for(:postfix_element) } - it { is_expected.to_not allow_value({}).for(:postfix_element)} - it { is_expected.to_not allow_value({type: 'info'}).for(:postfix_element)} - it { is_expected.to_not allow_value({ html_content: "We are going to
Something"}).for(:postfix_element)} + it { is_expected.to_not allow_value({}).for(:postfix_element) } + it { is_expected.to_not allow_value({type: "info"}).for(:postfix_element) } + it { is_expected.to_not allow_value({html_content: "We are going to
Something"}).for(:postfix_element) } end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 51df557e2..96ab3e786 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,24 +1,24 @@ -require 'simplecov' +require "simplecov" SimpleCov.start # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # This file is copied to spec/ when you run 'rails generate rspec:install' -ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) +ENV["RAILS_ENV"] ||= "test" +require File.expand_path("../../config/environment", __FILE__) # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? -require 'spec_helper' -require 'rspec/rails' -require 'devise' +require "spec_helper" +require "rspec/rails" +require "devise" # Add additional requires below this line. Rails is not loaded until this point! -require 'support/factory_bot' -require 'support/date_time' -require 'support/stripe_mock_helper' -require 'timecop' -require 'delayed_job' -require 'support/contexts' -require 'action_mailer_matchers' +require "support/factory_bot" +require "support/date_time" +require "support/stripe_mock_helper" +require "timecop" +require "delayed_job" +require "support/contexts" +require "action_mailer_matchers" Delayed::Worker.delay_jobs = false # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are @@ -37,12 +37,12 @@ RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - #config.fixture_path = "#{::Rails.root}/spec/fixtures" + # config.fixture_path = "#{::Rails.root}/spec/fixtures" # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. - #config.use_transactional_fixtures = true + # config.use_transactional_fixtures = true # RSpec Rails can automatically mix in different behaviours to your tests # based on their file location, for example enabling you to call `get` and @@ -63,7 +63,7 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") - config.include Devise::Test::ControllerHelpers, :type => :controller + config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::IntegrationHelpers, type: :request config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: /spec\/api/ @@ -77,7 +77,6 @@ config.include ActionMailerMatchers config.before(:suite) do - DatabaseCleaner.strategy = :transaction DatabaseCleaner.clean_with(:truncation, reset_ids: true) Rails.cache.clear diff --git a/spec/requests/api_new/object_events_controller_request_spec.rb b/spec/requests/api_new/object_events_controller_request_spec.rb index aa0235ba8..c83fa8543 100644 --- a/spec/requests/api_new/object_events_controller_request_spec.rb +++ b/spec/requests/api_new/object_events_controller_request_spec.rb @@ -2,116 +2,107 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe ApiNew::ObjectEventsController, type: :request do let(:user) { create(:user) } - let(:simple_object_with_parent) { create(:simple_object_with_parent)} - before(:each) { - simple_object_with_parent.publish_created - simple_object_with_parent.publish_updated - } - - - def index_base_path(nonprofit_id) - "/api_new/nonprofits/#{nonprofit_id}/object_events" - end - - def index_base_url(nonprofit_id, _event_id) - "http://www.example.com#{index_base_path(nonprofit_id)}" - end - - let(:nonprofit) { simple_object_with_parent.nonprofit} - - describe 'GET /' do - context 'with nonprofit user' do - subject(:json) do - JSON::parse(response.body) - end - - before(:each) do - user.roles.create(name: 'nonprofit_associate', host: nonprofit) - sign_in user - end - - - - context 'empty query' do + let(:simple_object_with_parent) { create(:simple_object_with_parent) } + before(:each) { + simple_object_with_parent.publish_created + simple_object_with_parent.publish_updated + } + + def index_base_path(nonprofit_id) + "/api_new/nonprofits/#{nonprofit_id}/object_events" + end + + def index_base_url(nonprofit_id, _event_id) + "http://www.example.com#{index_base_path(nonprofit_id)}" + end + + let(:nonprofit) { simple_object_with_parent.nonprofit } + + describe "GET /" do + context "with nonprofit user" do + subject(:json) do + JSON.parse(response.body) + end + + before(:each) do + user.roles.create(name: "nonprofit_associate", host: nonprofit) + sign_in user + end + + context "empty query" do before(:each) do get index_base_path(nonprofit.houid) end - it { - expect(json['total_count']).to eq 2 + expect(json["total_count"]).to eq 2 } end - - context 'with event_entity' do - context 'and entity doesnt exist' do + + context "with event_entity" do + context "and entity doesnt exist" do before(:each) do - get index_base_path(nonprofit.houid), params: {event_entity: 'fake_entity'} + get index_base_path(nonprofit.houid), params: {event_entity: "fake_entity"} end - + it { - expect(json['total_count']).to eq 0 + expect(json["total_count"]).to eq 0 } end - context 'and entity does exist' do + context "and entity does exist" do before(:each) do get index_base_path(nonprofit.houid), params: {event_entity: simple_object_with_parent.houid} end - + it { - expect(json['total_count']).to eq 2 + expect(json["total_count"]).to eq 2 } end - end - - context 'with event_types' do - context 'and event_types doesnt exist' do + + context "with event_types" do + context "and event_types doesnt exist" do before(:each) do - get index_base_path(nonprofit.houid), params: {event_types: ['soennoet.come']} + get index_base_path(nonprofit.houid), params: {event_types: ["soennoet.come"]} end - + it { - expect(json['total_count']).to eq 0 + expect(json["total_count"]).to eq 0 } end - context 'and event_types does exist' do + context "and event_types does exist" do before(:each) do - get index_base_path(nonprofit.houid), params: {event_types: ['simple_object.created']} + get index_base_path(nonprofit.houid), params: {event_types: ["simple_object.created"]} end - + it { - expect(json['total_count']).to eq 1 + expect(json["total_count"]).to eq 1 } end - context 'and multiple event_types do exist' do + context "and multiple event_types do exist" do before(:each) do - get index_base_path(nonprofit.houid), params: {event_entity: ['simple_object.created', 'simple_object.updated'] } + get index_base_path(nonprofit.houid), params: {event_entity: ["simple_object.created", "simple_object.updated"]} end - + it { - expect(json['total_count']).to eq 2 + expect(json["total_count"]).to eq 2 } end - end - - - - end - - context 'with no user' do - it 'returns unauthorized' do - get index_base_path(nonprofit.houid) - expect(response).to have_http_status(:unauthorized) - end - end - end + end + + context "with no user" do + it "returns unauthorized" do + get index_base_path(nonprofit.houid) + expect(response).to have_http_status(:unauthorized) + end + end + end end diff --git a/spec/requests/api_new/supporters_controller_request_spec.rb b/spec/requests/api_new/supporters_controller_request_spec.rb index 3fde73c6f..57fa9efbd 100644 --- a/spec/requests/api_new/supporters_controller_request_spec.rb +++ b/spec/requests/api_new/supporters_controller_request_spec.rb @@ -1,125 +1,120 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe ApiNew::SupportersController, type: :request do - let(:supporter) { create(:supporter_with_fv_poverty, :with_primary_address)} - let(:nonprofit) { supporter.nonprofit} + let(:supporter) { create(:supporter_with_fv_poverty, :with_primary_address) } + let(:nonprofit) { supporter.nonprofit } let(:user) { create(:user) } - before do - supporter - user.roles.create(name: 'nonprofit_associate', host: nonprofit) - end - describe 'routing for' do - describe 'api_new_nonprofit_supporter_path' do - subject {api_new_nonprofit_supporter_path(nonprofit.to_modern_param, supporter.to_modern_param)} - it {is_expected.to eq "/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}"} - end - - describe 'api_new_nonprofit_supporter_path' do - subject {api_new_nonprofit_supporter_url(nonprofit.to_modern_param, supporter.to_modern_param)} - it {is_expected.to eq "http://www.example.com/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}"} - end + before do + supporter + user.roles.create(name: "nonprofit_associate", host: nonprofit) end + describe "routing for" do + describe "api_new_nonprofit_supporter_path" do + subject { api_new_nonprofit_supporter_path(nonprofit.to_modern_param, supporter.to_modern_param) } + it { is_expected.to eq "/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}" } + end + describe "api_new_nonprofit_supporter_path" do + subject { api_new_nonprofit_supporter_url(nonprofit.to_modern_param, supporter.to_modern_param) } + it { is_expected.to eq "http://www.example.com/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}" } + end + end - describe 'GET /:id' do - context 'when logged in'do + describe "GET /:id" do + context "when logged in" do before do - sign_in user - get "/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}" - end - - it { - expect(response).to have_http_status(:success) - } - - - describe 'with a response' do - subject(:json) do - JSON.parse(response.body) - end - - let(:id) { json['id'] } - - it { - is_expected.to include('object' => 'supporter') - } - - it { - is_expected.to include('id' => supporter.houid) - } - - it { - is_expected.to include('name' => 'Fake Supporter Name') - } - - it { - is_expected.to include('nonprofit' => nonprofit.houid) - } - - it { - is_expected.to include('anonymous' => false) - } - - it { - is_expected.to include('deleted' => false) - } - - it { - is_expected.to include('merged_into' => nil) - } - - it { - is_expected.to include('organization' => nil) - } - - it { - is_expected.to include('phone' => nil) - } - - describe 'supporter_addresses' do - subject(:addresses) {json['supporter_addresses']} - it { - expect(addresses.count).to eq 1 - } - describe ' with the only address' do - subject(:sole_address) { addresses.first} - it { - is_expected.to include('address' => supporter.address) - } - - it { - is_expected.to include('city' => supporter.city) - } - - it { - is_expected.to include('state_code' => supporter.state_code) - } - - it { - is_expected.to include('zip_code' => supporter.zip_code) - } - - it { - is_expected.to include('country' => supporter.country) - } - end - end - - # it { - # is_expected.to include('url' => - # a_string_matching(%r{http://www\.example\.com/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}})) - # } - end - + sign_in user + get "/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}" + end + + it { + expect(response).to have_http_status(:success) + } + + describe "with a response" do + subject(:json) do + JSON.parse(response.body) + end + + let(:id) { json["id"] } + + it { + is_expected.to include("object" => "supporter") + } + + it { + is_expected.to include("id" => supporter.houid) + } + + it { + is_expected.to include("name" => "Fake Supporter Name") + } + + it { + is_expected.to include("nonprofit" => nonprofit.houid) + } + + it { + is_expected.to include("anonymous" => false) + } + + it { + is_expected.to include("deleted" => false) + } + + it { + is_expected.to include("merged_into" => nil) + } + + it { + is_expected.to include("organization" => nil) + } + + it { + is_expected.to include("phone" => nil) + } + + describe "supporter_addresses" do + subject(:addresses) { json["supporter_addresses"] } + it { + expect(addresses.count).to eq 1 + } + describe " with the only address" do + subject(:sole_address) { addresses.first } + it { + is_expected.to include("address" => supporter.address) + } + + it { + is_expected.to include("city" => supporter.city) + } + + it { + is_expected.to include("state_code" => supporter.state_code) + } + + it { + is_expected.to include("zip_code" => supporter.zip_code) + } + + it { + is_expected.to include("country" => supporter.country) + } + end + end + + # it { + # is_expected.to include('url' => + # a_string_matching(%r{http://www\.example\.com/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}})) + # } + end + end + it "returns unauthorized when not logged in" do + get "/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}" + expect(response).to have_http_status(:unauthorized) end - it 'returns unauthorized when not logged in' do - get "/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}" - expect(response).to have_http_status(:unauthorized) - end end - end - diff --git a/spec/requests/api_new/transactions_controller_request_spec.rb b/spec/requests/api_new/transactions_controller_request_spec.rb index 263923a73..d63818457 100644 --- a/spec/requests/api_new/transactions_controller_request_spec.rb +++ b/spec/requests/api_new/transactions_controller_request_spec.rb @@ -2,182 +2,177 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe ApiNew::TransactionsController, type: :request do - around do |ex| - Timecop.freeze(2020, 5, 4) do - ex.run - end - end - - let(:nonprofit) { transaction_for_donation.nonprofit } - let(:user) { create(:user) } - let(:supporter) { transaction_for_donation.supporter } - - let(:transaction_for_donation) do - create(:transaction_for_offline_donation) - end - - before do - transaction_for_donation - end - - def index_base_path(nonprofit_id) - "/api_new/nonprofits/#{nonprofit_id}/transactions" - end - - def index_base_url(nonprofit_id, _event_id) - "http://www.example.com#{index_base_path(nonprofit_id)}" - end - - describe 'GET /' do - context 'with nonprofit user' do - subject(:json) do - response.body - end - - before do - user.roles.create(name: 'nonprofit_associate', host: nonprofit) - sign_in user - get index_base_path(nonprofit.houid) - end - - it { - expect(response).to have_http_status(:success) - } - - describe 'for transaction_for_donation' do - - def base_path(nonprofit_id, transaction_id) - index_base_path(nonprofit_id) + "/#{transaction_id}" - end - - let(:transaction) { transaction_for_donation } - - def base_url(nonprofit_id, transaction_id) - "http://www.example.com#{base_path(nonprofit_id, transaction_id)}" - end - - it { - is_expected.to include_json( - first_page: true, - last_page: true, - current_page: 1, - requested_size: 25, - total_count: 1, - data: [ - attributes_for(:trx, - nonprofit: nonprofit.houid, - supporter: attributes_for( - :supporter_expectation, - id: supporter.houid - ), - id: transaction.houid, - amount_cents: 4000, - subtransaction: attributes_for( - :subtransaction_expectation, - :offline_transaction, - gross_amount_cents: 4000, - net_amount_cents: 4000, - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ] - ), - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ], - transaction_assignments: [ - attributes_for(:trx_assignment_expectation, - :donation, - amount_cents:4000, - designation: "Designation 1" - ) - ] - )] - - )} - end - - end - - context 'with no user' do - it 'returns unauthorized' do - get index_base_path(nonprofit.houid) - expect(response).to have_http_status(:unauthorized) - end - end - end - - describe 'GET /:transaction_id' do - def show_base_path(nonprofit_id, transaction_id) - index_base_path(nonprofit_id) + "/" + transaction_id - end - - context 'with nonprofit user' do - subject(:json) do - response.body - end - - before do - user.roles.create(name: 'nonprofit_associate', host: nonprofit) - sign_in user - get show_base_path(nonprofit.houid, transaction_for_donation.houid) - end - - it { - expect(response).to have_http_status(:success) - } - - it { - is_expected.to include_json(attributes_for(:trx, - nonprofit: nonprofit.houid, - supporter: attributes_for( - :supporter_expectation, - id: supporter.houid - ), - id: transaction_for_donation.houid, - amount_cents: 4000, - subtransaction: attributes_for( - :subtransaction_expectation, - :offline_transaction, - gross_amount_cents: 4000, - net_amount_cents: 4000, - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ] - ), - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ], - transaction_assignments: [ - attributes_for(:trx_assignment_expectation, - :donation, - amount_cents:4000, - designation: "Designation 1" - ) - ] - )) - } - end - - context 'with no user' do - it 'returns unauthorized' do - get show_base_path(nonprofit.id, transaction_for_donation.houid) - expect(response).to have_http_status(:unauthorized) - end - end - end + around do |ex| + Timecop.freeze(2020, 5, 4) do + ex.run + end + end + + let(:nonprofit) { transaction_for_donation.nonprofit } + let(:user) { create(:user) } + let(:supporter) { transaction_for_donation.supporter } + + let(:transaction_for_donation) do + create(:transaction_for_offline_donation) + end + + before do + transaction_for_donation + end + + def index_base_path(nonprofit_id) + "/api_new/nonprofits/#{nonprofit_id}/transactions" + end + + def index_base_url(nonprofit_id, _event_id) + "http://www.example.com#{index_base_path(nonprofit_id)}" + end + + describe "GET /" do + context "with nonprofit user" do + subject(:json) do + response.body + end + + before do + user.roles.create(name: "nonprofit_associate", host: nonprofit) + sign_in user + get index_base_path(nonprofit.houid) + end + + it { + expect(response).to have_http_status(:success) + } + + describe "for transaction_for_donation" do + def base_path(nonprofit_id, transaction_id) + index_base_path(nonprofit_id) + "/#{transaction_id}" + end + + let(:transaction) { transaction_for_donation } + + def base_url(nonprofit_id, transaction_id) + "http://www.example.com#{base_path(nonprofit_id, transaction_id)}" + end + + it { + is_expected.to include_json( + first_page: true, + last_page: true, + current_page: 1, + requested_size: 25, + total_count: 1, + data: [ + attributes_for(:trx, + nonprofit: nonprofit.houid, + supporter: attributes_for( + :supporter_expectation, + id: supporter.houid + ), + id: transaction.houid, + amount_cents: 4000, + subtransaction: attributes_for( + :subtransaction_expectation, + :offline_transaction, + gross_amount_cents: 4000, + net_amount_cents: 4000, + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ] + ), + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ], + transaction_assignments: [ + attributes_for(:trx_assignment_expectation, + :donation, + amount_cents: 4000, + designation: "Designation 1") + ]) + ] + ) + } + end + end + + context "with no user" do + it "returns unauthorized" do + get index_base_path(nonprofit.houid) + expect(response).to have_http_status(:unauthorized) + end + end + end + + describe "GET /:transaction_id" do + def show_base_path(nonprofit_id, transaction_id) + index_base_path(nonprofit_id) + "/" + transaction_id + end + + context "with nonprofit user" do + subject(:json) do + response.body + end + + before do + user.roles.create(name: "nonprofit_associate", host: nonprofit) + sign_in user + get show_base_path(nonprofit.houid, transaction_for_donation.houid) + end + + it { + expect(response).to have_http_status(:success) + } + + it { + is_expected.to include_json(attributes_for(:trx, + nonprofit: nonprofit.houid, + supporter: attributes_for( + :supporter_expectation, + id: supporter.houid + ), + id: transaction_for_donation.houid, + amount_cents: 4000, + subtransaction: attributes_for( + :subtransaction_expectation, + :offline_transaction, + gross_amount_cents: 4000, + net_amount_cents: 4000, + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ] + ), + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ], + transaction_assignments: [ + attributes_for(:trx_assignment_expectation, + :donation, + amount_cents: 4000, + designation: "Designation 1") + ])) + } + end + + context "with no user" do + it "returns unauthorized" do + get show_base_path(nonprofit.id, transaction_for_donation.houid) + expect(response).to have_http_status(:unauthorized) + end + end + end end diff --git a/spec/requests/api_new/users_controller_request_spec.rb b/spec/requests/api_new/users_controller_request_spec.rb index cecfdcd12..aa3ffc1a8 100644 --- a/spec/requests/api_new/users_controller_request_spec.rb +++ b/spec/requests/api_new/users_controller_request_spec.rb @@ -1,142 +1,135 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe ApiNew::UsersController, type: :request do + context "for unlogged in user" do + it "returns unauthorized when not logged in" do + get "/api_new/users/current" + expect(response).to have_http_status(:unauthorized) + end + end + + context "for a nonprofit admin" do + let(:user) { create(:user_base, roles: [build(:role_base, :as_nonprofit_admin)]) } + + subject(:body) { response.body } + before do + sign_in user + get "/api_new/users/current" + end + + it { + expect(response).to have_http_status(:success) + } + + it { + is_expected.to include_json( + object: "user", + is_super_admin: false, + roles: [ + { + host: Nonprofit.first.to_houid + } + ] + ) + } + end + + context "for a nonprofit associate" do + let(:user) { create(:user_as_nonprofit_associate) } + + subject(:body) { response.body } + before do + sign_in user + get "/api_new/users/current" + end + + it { + expect(response).to have_http_status(:success) + } + + it { + is_expected.to include_json( + object: "user", + is_super_admin: false, + roles: [] + ) + } + end + + context "for super admin" do + let(:user) { create(:user_as_super_admin) } + + subject(:body) { response.body } + before do + sign_in user + get "/api_new/users/current" + end + + it { + expect(response).to have_http_status(:success) + } + + it { + is_expected.to include_json( + object: "user", + is_super_admin: true, + roles: [] + ) + } + end + + context "test using basic auth (testing that Devise.http_authenticatable works)" do + let(:user) { create(:user_as_nonprofit_associate, password: "valid_password") } + + subject(:body) { response.body } + describe "with correct password" do + before do + get "/api_new/users/current", headers: {authorization: "Basic #{Base64.encode64("#{user.email}:valid_password")}"} + end - context 'for unlogged in user' do - it 'returns unauthorized when not logged in' do - get "/api_new/users/current" - expect(response).to have_http_status(:unauthorized) - end - end - - context 'for a nonprofit admin' do - - let(:user) {create(:user_base, roles:[build(:role_base, :as_nonprofit_admin) ])} - - - subject(:body) { response.body} - before do - sign_in user - get "/api_new/users/current" - end - - it { - expect(response).to have_http_status(:success) - } - - it { - is_expected.to include_json( - object: 'user', - is_super_admin: false, - roles: [ - { - host: Nonprofit.first.to_houid - } - ]) - } - - end - - context 'for a nonprofit associate' do - let(:user) {create(:user_as_nonprofit_associate)} - - subject(:body) { response.body} - before do - sign_in user - get "/api_new/users/current" - end - - it { - expect(response).to have_http_status(:success) - } - - it { - is_expected.to include_json( - object: 'user', - is_super_admin: false, - roles: [] - ) - } - - end - - context "for super admin" do - let(:user) {create(:user_as_super_admin )} - - subject(:body) { response.body} - before do - sign_in user - get "/api_new/users/current" - end - - it { - expect(response).to have_http_status(:success) - } - - it { - is_expected.to include_json( - object: 'user', - is_super_admin: true, - roles: [] - ) - } - end - - context 'test using basic auth (testing that Devise.http_authenticatable works)' do - let(:user) {create(:user_as_nonprofit_associate, password: 'valid_password')} - - - - subject(:body) { response.body} - - describe "with correct password" do - before do - get "/api_new/users/current", headers: {authorization: "Basic #{Base64.encode64("#{user.email}:valid_password")}"} - end - - it { - expect(response).to have_http_status(:success) - } - end - - describe "with incorrect password" do - before do - get "/api_new/users/current", headers: {authorization: "Basic #{Base64.encode64("#{user.email}:BAD_PASSWORD")}"} - end - - it { - expect(response).to have_http_status(:unauthorized) - } - end + it { + expect(response).to have_http_status(:success) + } + end + + describe "with incorrect password" do + before do + get "/api_new/users/current", headers: {authorization: "Basic #{Base64.encode64("#{user.email}:BAD_PASSWORD")}"} + end + + it { + expect(response).to have_http_status(:unauthorized) + } + end end - context 'GET /api_new/users/current_nonprofit_object_events' do - let(:nonprofit_user) { create(:user_as_nonprofit_associate) } - let(:no_nonprofit_user) { create(:user) } + context "GET /api_new/users/current_nonprofit_object_events" do + let(:nonprofit_user) { create(:user_as_nonprofit_associate) } + let(:no_nonprofit_user) { create(:user) } - it "redirects to api_new/object_events#index for the user's nonprofit when the user has one" do - sign_in nonprofit_user - get current_nonprofit_object_events_api_new_users_path + it "redirects to api_new/object_events#index for the user's nonprofit when the user has one" do + sign_in nonprofit_user + get current_nonprofit_object_events_api_new_users_path - np_houid = nonprofit_user.roles.where(host_type: 'Nonprofit').first&.host&.houid - expect(response).to redirect_to controller: 'api_new/object_events', action: 'index', nonprofit_id: np_houid - end + np_houid = nonprofit_user.roles.where(host_type: "Nonprofit").first&.host&.houid + expect(response).to redirect_to controller: "api_new/object_events", action: "index", nonprofit_id: np_houid + end - it "passes query params" do - sign_in nonprofit_user - get current_nonprofit_object_events_api_new_users_path({foo: 'bar', baz: 'qux'}) + it "passes query params" do + sign_in nonprofit_user + get current_nonprofit_object_events_api_new_users_path({foo: "bar", baz: "qux"}) - np_houid = nonprofit_user.roles.where(host_type: 'Nonprofit').first&.host&.houid - expect(response).to redirect_to controller: 'api_new/object_events', action: 'index', nonprofit_id: np_houid, foo: 'bar', baz: 'qux' - end + np_houid = nonprofit_user.roles.where(host_type: "Nonprofit").first&.host&.houid + expect(response).to redirect_to controller: "api_new/object_events", action: "index", nonprofit_id: np_houid, foo: "bar", baz: "qux" + end - it "returns a 404 not found when user doesn't have a nonprofit" do - sign_in no_nonprofit_user - get current_nonprofit_object_events_api_new_users_path + it "returns a 404 not found when user doesn't have a nonprofit" do + sign_in no_nonprofit_user + get current_nonprofit_object_events_api_new_users_path - expect(response).to have_http_status(:not_found) - end - end + expect(response).to have_http_status(:not_found) + end + end end diff --git a/spec/requests/campaigns/campaign_gift_options_request_spec.rb b/spec/requests/campaigns/campaign_gift_options_request_spec.rb index 9d46b8605..241495011 100644 --- a/spec/requests/campaigns/campaign_gift_options_request_spec.rb +++ b/spec/requests/campaigns/campaign_gift_options_request_spec.rb @@ -1,8 +1,7 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Campaigns::CampaignGiftOptionsController, type: :request do - let!(:campaign_gift_option) { create(:campaign_gift_option_base) } let(:campaign) { campaign_gift_option.campaign } let(:nonprofit) { campaign.nonprofit } @@ -15,7 +14,7 @@ it "returns properly" do get campaigns_campaign_gift_options_path(nonprofit_id: nonprofit.id, campaign_id: campaign.id), params: {format: :json} - expect(JSON::parse(response.body)).to match "data" => [] # NOTE: this doesn't include campaign gift options if they don't have any donations. Why? Bad design, I think. + expect(JSON.parse(response.body)).to match "data" => [] # NOTE: this doesn't include campaign gift options if they don't have any donations. Why? Bad design, I think. expect(response).to have_http_status(:success) end end diff --git a/spec/requests/cards_spec.rb b/spec/requests/cards_spec.rb index 376883307..62dd0dea8 100644 --- a/spec/requests/cards_spec.rb +++ b/spec/requests/cards_spec.rb @@ -1,25 +1,23 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe CardsController, type: :request do - describe 'throttling' do + describe "throttling" do before(:each) do - stub_const('FORCE_THROTTLE', true) + stub_const("FORCE_THROTTLE", true) end - let!(:supporter) { create(:supporter_base)} - it 'test number of card throttle' do + let!(:supporter) { create(:supporter_base) } + it "test number of card throttle" do 6.times { - post '/cards', params: {card:{holder_type:'Supporter', holder_id: supporter.id}}.to_json, headers: {"CONTENT_TYPE" => "application/json" } + post "/cards", params: {card: {holder_type: "Supporter", holder_id: supporter.id}}.to_json, headers: {"CONTENT_TYPE" => "application/json"} } expect(response.status.to_s).to start_with "4" Timecop.freeze(61) do - post '/cards', params: {card:{holder_type:'Supporter', holder_id: supporter.id}}.to_json, headers: {"CONTENT_TYPE" => "application/json" } + post "/cards", params: {card: {holder_type: "Supporter", holder_id: supporter.id}}.to_json, headers: {"CONTENT_TYPE" => "application/json"} expect(@response.status).to_not eq 429 end - end end end - diff --git a/spec/requests/events_request_spec.rb b/spec/requests/events_request_spec.rb index 4c82c0c50..d4c712f21 100644 --- a/spec/requests/events_request_spec.rb +++ b/spec/requests/events_request_spec.rb @@ -1,39 +1,35 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe EventsController, type: :request do - def event_setup nonprofit = create(:nonprofit_base) OpenStruct.new( - deleted: create(:event_base, nonprofit: nonprofit, deleted: true), - last: create(:event_base, nonprofit: nonprofit, name: "Last event"), - first: create(:event_base, nonprofit: nonprofit, name: "First event"), - nonprofit: nonprofit) - + deleted: create(:event_base, nonprofit: nonprofit, deleted: true), + last: create(:event_base, nonprofit: nonprofit, name: "Last event"), + first: create(:event_base, nonprofit: nonprofit, name: "First event"), + nonprofit: nonprofit + ) end def login_as_associate(nonprofit) - user = create(:user_base, roles:[build(:role_base, name: 'nonprofit_associate', host: nonprofit)]) + user = create(:user_base, roles: [build(:role_base, name: "nonprofit_associate", host: nonprofit)]) sign_in user end - it 'contains the events in order from first, to last with no deleted events' do - Event.any_instance.stub(:geocode).and_return([1,1]) # otherwise the geocode call fails + it "contains the events in order from first, to last with no deleted events" do + Event.any_instance.stub(:geocode).and_return([1, 1]) # otherwise the geocode call fails events = event_setup login_as_associate(events.nonprofit) get "/nonprofits/#{events.nonprofit.id}/events/name_and_id" - result = JSON::parse(response.body) + result = JSON.parse(response.body) expect(result).to include_json([ {name: events.first.name, id: events.first.id}, {name: events.last.name, id: events.last.id} ]) - end - - -end \ No newline at end of file +end diff --git a/spec/requests/maintenance_spec.rb b/spec/requests/maintenance_spec.rb index dc68eb0b7..7cc1111b0 100644 --- a/spec/requests/maintenance_spec.rb +++ b/spec/requests/maintenance_spec.rb @@ -1,8 +1,8 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' -require 'controllers/support/shared_user_context' +require "rails_helper" +require "controllers/support/shared_user_context" -describe 'Maintenance Mode' do +describe "Maintenance Mode" do page = "http://commet" token = "thoathioa" include_context :shared_user_context @@ -12,13 +12,13 @@ end describe OnboardController, type: :controller do - describe '(Onboard is just a basic example controller)' - it 'not in maintenance mode' do + describe "(Onboard is just a basic example controller)" + it "not in maintenance mode" do get :index assert_response 200 end - describe 'in maintenance' do + describe "in maintenance" do before(:each) do Settings.merge!({maintenance: {maintenance_mode: true, @@ -26,12 +26,12 @@ maintenance_page: page}}) end - it 'redirects for onboard' do + it "redirects for onboard" do get :index assert_redirected_to page end - it 'allows access to non-sign_in pages if youre logged in' do + it "allows access to non-sign_in pages if youre logged in" do sign_in user_as_np_associate get :index assert_response 200 @@ -40,16 +40,14 @@ end describe Users::SessionsController, type: :request do - describe 'in maintenance' do + describe "in maintenance" do include_context :shared_user_context around(:each) do |example| example.run Settings.reload! end - - - describe 'in maintenance' do + describe "in maintenance" do before(:each) do Settings.merge!({maintenance: {maintenance_mode: true, @@ -57,39 +55,37 @@ maintenance_page: page}}) end - it 'redirects sign_in if the token is wrong' do - get('/users/sign_in', params: {maintenance_token: "#{token}3"}) + it "redirects sign_in if the token is wrong" do + get("/users/sign_in", params: {maintenance_token: "#{token}3"}) expect(response.code).to eq "302" expect(response.location).to eq page end - it 'redirects for login' do - get('/users/sign_in') + it "redirects for login" do + get("/users/sign_in") expect(response.code).to eq "302" expect(response.location).to eq page end - - it 'redirects sign_in if the token is passed in wrong param' do - get('/users/sign_in', params: {maintnancerwrwer_token: "#{token}"}) + it "redirects sign_in if the token is passed in wrong param" do + get("/users/sign_in", params: {maintnancerwrwer_token: "#{token}"}) expect(response.code).to eq "302" expect(response.location).to eq page end - it 'allows visiting sign_in if the token is passed' do - get('/users/sign_in', params: {maintenance_token: "#{token}"}) - expect(response.code).to eq '200' + it "allows visiting sign_in if the token is passed" do + get("/users/sign_in", params: {maintenance_token: "#{token}"}) + expect(response.code).to eq "200" end - it 'allows sign_in.json' do - post('/users/sign_in.json', params: {maintenance_token: "#{token}", format: 'json'}) - expect(response.code).to_not eq '302' + it "allows sign_in.json" do + post("/users/sign_in.json", params: {maintenance_token: "#{token}", format: "json"}) + expect(response.code).to_not eq "302" end end end - describe 'in maintenance without maintenance_token set' do - + describe "in maintenance without maintenance_token set" do before(:each) do Settings.merge!({maintenance: {maintenance_mode: true, @@ -97,13 +93,11 @@ maintenance_page: page}}) end - it 'redirects sign_in if the token is nil' do - get('/users/sign_in') + it "redirects sign_in if the token is nil" do + get("/users/sign_in") expect(response.code).to eq "302" expect(response.location).to eq page end end - end end - diff --git a/spec/requests/nonprofits/direct_debit_details_spec.rb b/spec/requests/nonprofits/direct_debit_details_spec.rb index 35e13b465..3f5e1ef97 100644 --- a/spec/requests/nonprofits/direct_debit_details_spec.rb +++ b/spec/requests/nonprofits/direct_debit_details_spec.rb @@ -1,12 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe DirectDebitDetailsController, type: :request do - describe 'POST /sepa' do + describe "POST /sepa" do let!(:nonprofit) { Nonprofit.create(name: "new", city: "NY", state_code: "NY") } let(:supporter) { Supporter.create(nonprofit: nonprofit) } - let(:valid_params) do { + let(:valid_params) do + { supporter_id: supporter.id, sepa_params: { iban: "iban", @@ -16,22 +17,22 @@ } end - describe 'requires params' do - it 'is valid when sepa_params, donation_id and supporter_id are present' do + describe "requires params" do + it "is valid when sepa_params, donation_id and supporter_id are present" do post "/sepa", params: valid_params assert_response 200 assert_equal nil, JSON.parse(@response.body)["errors"] end - it 'is not valid without sepa_params' do + it "is not valid without sepa_params" do post "/sepa", params: valid_params.except(:sepa_params) assert_response 422 assert_equal ["sepa_params required"], JSON.parse(@response.body)["errors"] end - it 'is not valid without supporter_id' do + it "is not valid without supporter_id" do post "/sepa", params: valid_params.except(:supporter_id) assert_response 422 diff --git a/spec/requests/nonprofits/donations_controller_request_spec.rb b/spec/requests/nonprofits/donations_controller_request_spec.rb index 8ad6eb605..010f0af0b 100644 --- a/spec/requests/nonprofits/donations_controller_request_spec.rb +++ b/spec/requests/nonprofits/donations_controller_request_spec.rb @@ -2,10 +2,9 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe Nonprofits::DonationsController, type: :request do - def create_stripe_base_path(nonprofit_id) "/nonprofits/#{nonprofit_id}/donations" end @@ -14,81 +13,77 @@ def create_offsite_base_path(nonprofit_id) "/nonprofits/#{nonprofit_id}/donations/create_offsite" end - around do |ex| - Timecop.freeze(2020, 5, 4) do - ex.run - end - end + around do |ex| + Timecop.freeze(2020, 5, 4) do + ex.run + end + end - describe 'POST /create_offsite' do - let(:supporter) {create(:supporter_with_fv_poverty)} - let(:nonprofit) { supporter.nonprofit} - let(:user) { create(:user_as_nonprofit_associate, nonprofit: nonprofit) } - context 'with nonprofit user' do + describe "POST /create_offsite" do + let(:supporter) { create(:supporter_with_fv_poverty) } + let(:nonprofit) { supporter.nonprofit } + let(:user) { create(:user_as_nonprofit_associate, nonprofit: nonprofit) } + context "with nonprofit user" do before do - sign_in user + sign_in user post create_offsite_base_path(nonprofit.id), params: {donation: { amount: 4000, supporter_id: supporter.id, nonprofit_id: nonprofit.id, designation: "Designation 1", - dedication: {note: "My mom", type:"honor"}.to_json + dedication: {note: "My mom", type: "honor"}.to_json }} end let(:transaction) { - payment_id = JSON.parse(response.body)['payment']['id'] + payment_id = JSON.parse(response.body)["payment"]["id"] Payment.find(payment_id).trx } - subject(:transaction_result) do - + subject(:transaction_result) do get "/api_new/nonprofits/#{nonprofit.houid}/transactions/#{transaction.houid}" response.body end - describe 'result' do - + describe "result" do it { is_expected.to include_json(attributes_for(:trx, - nonprofit: nonprofit.houid, - supporter: attributes_for( - :supporter_expectation, - id: supporter.houid - ), - id: transaction.houid, - amount_cents: 4000, - subtransaction: attributes_for( - :subtransaction_expectation, - :offline_transaction, - gross_amount_cents: 4000, - net_amount_cents: 4000, + nonprofit: nonprofit.houid, + supporter: attributes_for( + :supporter_expectation, + id: supporter.houid + ), + id: transaction.houid, + amount_cents: 4000, + subtransaction: attributes_for( + :subtransaction_expectation, + :offline_transaction, + gross_amount_cents: 4000, + net_amount_cents: 4000, + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ] + ), payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ] - ), - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ], - transaction_assignments: [ - attributes_for(:trx_assignment_expectation, - :donation, - amount_cents:4000, - designation: "Designation 1" - ) - ] - )) + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ], + transaction_assignments: [ + attributes_for(:trx_assignment_expectation, + :donation, + amount_cents: 4000, + designation: "Designation 1") + ])) } end - describe 'object events' do - subject(:transaction_event) do + describe "object events" do + subject(:transaction_event) do get "/api_new/nonprofits/#{nonprofit.houid}/object_events", params: {event_entity: transaction.houid} response.body end @@ -97,32 +92,32 @@ def create_offsite_base_path(nonprofit_id) is_expected.to include_json( data: [ { - id: match_houid('evt'), - type: 'transaction.created', + id: match_houid("evt"), + type: "transaction.created", created: be_a(Numeric), - object: 'object_event', + object: "object_event", data: { object: { - 'id' => transaction.houid, - 'supporter' => transaction.supporter.houid, + "id" => transaction.houid, + "supporter" => transaction.supporter.houid, - 'subtransaction' => { - 'id' => match_houid(:offlinetrx), - 'amount' => {'cents' => 4000, 'currency' => 'usd'}, - 'payments' => [ + "subtransaction" => { + "id" => match_houid(:offlinetrx), + "amount" => {"cents" => 4000, "currency" => "usd"}, + "payments" => [ { - 'id' => match_houid(:offtrxchrg), - 'gross_amount' => {'cents' => 4000, 'currency' => 'usd'}, - 'fee_total' => {'cents' => 0, 'currency' => 'usd'}, - 'net_amount' => {'cents' => 4000, 'currency' => 'usd'} + "id" => match_houid(:offtrxchrg), + "gross_amount" => {"cents" => 4000, "currency" => "usd"}, + "fee_total" => {"cents" => 0, "currency" => "usd"}, + "net_amount" => {"cents" => 4000, "currency" => "usd"} } ] }, - 'transaction_assignments' => [ + "transaction_assignments" => [ { - 'id' => match_houid('don'), - designation: 'Designation 1', - dedication: { + "id" => match_houid("don"), + :designation => "Designation 1", + :dedication => { note: "My mom", type: "honor" } @@ -130,44 +125,41 @@ def create_offsite_base_path(nonprofit_id) ] } } - } + } ] ) } - - end + end end - context 'without nonprofit user' do - it 'returns unauthorized' do - post create_offsite_base_path(nonprofit.id) - expect(response).to have_http_status(302) - end + context "without nonprofit user" do + it "returns unauthorized" do + post create_offsite_base_path(nonprofit.id) + expect(response).to have_http_status(302) + end end end - describe 'POST /create' do - + describe "POST /create" do around(:each) do |ex| - StripeMockHelper.mock do + StripeMockHelper.mock do ex.run - end + end end - let(:supporter) {create(:supporter, nonprofit: nonprofit)} + let(:supporter) { create(:supporter, nonprofit: nonprofit) } let(:nonprofit) do - stripe_account = create(:stripe_account, charges_enabled:true) - create(:nonprofit, stripe_account_id: stripe_account.stripe_account_id) + stripe_account = create(:stripe_account, charges_enabled: true) + create(:nonprofit, stripe_account_id: stripe_account.stripe_account_id) end let(:user) { create(:user_base, roles: [build(:role_base, :as_nonprofit_associate, host: nonprofit)]) } - - let(:token) { create(:source_token_base, tokenizable: create(:card_base, :with_created_stripe_customer_and_card, holder: supporter))} - context 'with non-logged-in user' do + let(:token) { create(:source_token_base, tokenizable: create(:card_base, :with_created_stripe_customer_and_card, holder: supporter)) } + context "with non-logged-in user" do def prepare_fee_eras create(:fee_era_with_structures) end - + subject(:main_response) { prepare_fee_eras post create_stripe_base_path(nonprofit.id), params: {donation: { @@ -175,139 +167,127 @@ def prepare_fee_eras supporter_id: supporter.id, nonprofit_id: nonprofit.id, designation: "Designation 1", - dedication: {note: "My mom", type:"honor"}.to_json + dedication: {note: "My mom", type: "honor"}.to_json }, token: token.token, amount: 4000} response } - it { is_expected.to have_http_status(:ok) } - - - context 'transaction json' do + context "transaction json" do let(:transaction) { - - payment_id = JSON.parse(main_response.body)['payment']['id'] + payment_id = JSON.parse(main_response.body)["payment"]["id"] Payment.find(payment_id).trx } - subject(:transaction_result) do + subject(:transaction_result) do sign_in user get "/api_new/nonprofits/#{nonprofit.houid}/transactions/#{transaction.houid}" response.body end - describe 'result' do - - + describe "result" do it { is_expected.to include_json( attributes_for(:trx, - nonprofit: nonprofit.houid, - supporter: attributes_for( - :supporter_expectation, - id: supporter.houid - ), - id: transaction.houid, - amount_cents: 4000, - subtransaction: attributes_for( - :subtransaction_expectation, - :stripe_transaction, - gross_amount_cents: 4000, - net_amount_cents: 4000 - 250, + nonprofit: nonprofit.houid, + supporter: attributes_for( + :supporter_expectation, + id: supporter.houid + ), + id: transaction.houid, + amount_cents: 4000, + subtransaction: attributes_for( + :subtransaction_expectation, + :stripe_transaction, + gross_amount_cents: 4000, + net_amount_cents: 4000 - 250, + payments: [ + attributes_for(:payment_expectation, + :stripe_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: -250) + ] + ), payments: [ - attributes_for(:payment_expectation, - :stripe_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: -250) - ] - ), - payments: [ - attributes_for(:payment_expectation, - :stripe_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: -250) - ], - transaction_assignments: [ - attributes_for(:trx_assignment_expectation, - :donation, - amount_cents: 4000, - designation: "Designation 1", - legacy_id: transaction.donations.first.legacy_id, - dedication: { - note: "My mom", - type: "honor" - } - ) - ] - ) - ) + attributes_for(:payment_expectation, + :stripe_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: -250) + ], + transaction_assignments: [ + attributes_for(:trx_assignment_expectation, + :donation, + amount_cents: 4000, + designation: "Designation 1", + legacy_id: transaction.donations.first.legacy_id, + dedication: { + note: "My mom", + type: "honor" + }) + ]) + ) } - describe 'object events' do - describe 'transaction.created' do + describe "object events" do + describe "transaction.created" do subject(:transaction_event) do sign_in user get "/api_new/nonprofits/#{nonprofit.houid}/object_events", params: {event_entity: transaction.houid} response.body end - it { is_expected.to include_json( data: [ { - id: match_houid('evt'), - type: 'transaction.created', + id: match_houid("evt"), + type: "transaction.created", created: be_a(Numeric), - object: 'object_event', + object: "object_event", data: { object: attributes_for(:trx, - nonprofit: nonprofit.houid, - supporter: supporter.houid, - id: transaction.houid, - amount_cents: 4000, - subtransaction: attributes_for( - :subtransaction_expectation, - :stripe_transaction, - gross_amount_cents: 4000, - net_amount_cents: 4000 - 250, + nonprofit: nonprofit.houid, + supporter: supporter.houid, + id: transaction.houid, + amount_cents: 4000, + subtransaction: attributes_for( + :subtransaction_expectation, + :stripe_transaction, + gross_amount_cents: 4000, + net_amount_cents: 4000 - 250, + payments: [ + attributes_for(:payment_expectation, + :stripe_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: -250) + ] + ), payments: [ - attributes_for(:payment_expectation, - :stripe_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: -250) - ] - ), - payments: [ - match_houid(:stripechrg) - ], - transaction_assignments: [ - attributes_for(:trx_assignment_expectation, - :donation, - amount_cents: 4000, - designation: "Designation 1", - legacy_id: transaction.donations.first.legacy_id, - dedication: { - note: "My mom", - type: "honor" - } - ) - ] - ) + match_houid(:stripechrg) + ], + transaction_assignments: [ + attributes_for(:trx_assignment_expectation, + :donation, + amount_cents: 4000, + designation: "Designation 1", + legacy_id: transaction.donations.first.legacy_id, + dedication: { + note: "My mom", + type: "honor" + }) + ]) } - } + } ] - ) - + ) } end - describe 'stripe_transaction_charge.created' do - let(:stripe_charge) { transaction.payments.first} + describe "stripe_transaction_charge.created" do + let(:stripe_charge) { transaction.payments.first } subject(:charge_event) do sign_in user get "/api_new/nonprofits/#{nonprofit.houid}/object_events", params: {event_entity: stripe_charge.to_houid} @@ -315,36 +295,35 @@ def prepare_fee_eras end it { - is_expected.to include_json( data: [ { - id: match_houid('evt'), - type: 'stripe_transaction_charge.created', + id: match_houid("evt"), + type: "stripe_transaction_charge.created", created: be_a(Numeric), - object: 'object_event', + object: "object_event", data: { object: { - 'id' => stripe_charge.to_houid, - 'supporter' => { - 'id' => stripe_charge.supporter.houid + "id" => stripe_charge.to_houid, + "supporter" => { + "id" => stripe_charge.supporter.houid }, - 'gross_amount' => {'cents' => 4000, 'currency' => 'usd'}, - 'fee_total' => {'cents' => -250, 'currency' => 'usd'}, - 'net_amount' => {'cents' => 3750, 'currency' => 'usd'}, - created: be_a(Numeric), - subtransaction: { - id: match_houid(:stripetrx), - 'amount' => {'cents' => 4000, 'currency' => 'usd'}, - payments: [{id: stripe_charge.to_houid}], - transaction: { - 'amount' => {'cents' => 4000, 'currency' => 'usd'}, - 'transaction_assignments' => [ + "gross_amount" => {"cents" => 4000, "currency" => "usd"}, + "fee_total" => {"cents" => -250, "currency" => "usd"}, + "net_amount" => {"cents" => 3750, "currency" => "usd"}, + :created => be_a(Numeric), + :subtransaction => { + :id => match_houid(:stripetrx), + "amount" => {"cents" => 4000, "currency" => "usd"}, + :payments => [{id: stripe_charge.to_houid}], + :transaction => { + "amount" => {"cents" => 4000, "currency" => "usd"}, + "transaction_assignments" => [ { - 'id' => match_houid('don'), - designation: 'Designation 1', - legacy_id: transaction.donations.first.legacy_id, - dedication: { + "id" => match_houid("don"), + :designation => "Designation 1", + :legacy_id => transaction.donations.first.legacy_id, + :dedication => { note: "My mom", type: "honor" } @@ -354,15 +333,14 @@ def prepare_fee_eras } } } - } + } ] - ) + ) } end - - describe 'donation.created' do - let(:donation) { transaction.donations.first} + describe "donation.created" do + let(:donation) { transaction.donations.first } subject(:donation_event) do sign_in user get "/api_new/nonprofits/#{nonprofit.houid}/object_events", params: {event_entity: donation.to_houid} @@ -373,54 +351,54 @@ def prepare_fee_eras is_expected.to include_json( data: [ { - id: match_houid('evt'), - type: 'donation.created', + id: match_houid("evt"), + type: "donation.created", created: be_a(Numeric), - object: 'object_event', + object: "object_event", data: { object: { - 'id' => donation.to_houid, - 'supporter' => donation.supporter.houid, - object: 'donation', - 'amount' => {'cents' => 4000, 'currency' => 'usd'}, - designation: 'Designation 1', - legacy_id: donation.legacy_id, - dedication: { + "id" => donation.to_houid, + "supporter" => donation.supporter.houid, + :object => "donation", + "amount" => {"cents" => 4000, "currency" => "usd"}, + :designation => "Designation 1", + :legacy_id => donation.legacy_id, + :dedication => { note: "My mom", type: "honor" }, # created: be_a(Numeric), - transaction: { - subtransaction: { - id: match_houid(:stripetrx), - 'amount' => {'cents' => 4000, 'currency' => 'usd'}, - payments: [{id: match_houid(:stripechrg)}], - transaction: match_houid(:trx) + :transaction => { + :subtransaction => { + :id => match_houid(:stripetrx), + "amount" => {"cents" => 4000, "currency" => "usd"}, + :payments => [{id: match_houid(:stripechrg)}], + :transaction => match_houid(:trx) }, - 'transaction_assignments' => [ + "transaction_assignments" => [ { - 'id' => match_houid('don'), - designation: 'Designation 1', - legacy_id: donation.legacy_id, - dedication: { + "id" => match_houid("don"), + :designation => "Designation 1", + :legacy_id => donation.legacy_id, + :dedication => { note: "My mom", type: "honor" } } ] - }, - + } + } - + } - } + } ] - ) + ) } end - end + end end end end end -end \ No newline at end of file +end diff --git a/spec/requests/nonprofits/payments_controller_spec.rb b/spec/requests/nonprofits/payments_controller_spec.rb index 0e1a91065..6a61166a5 100644 --- a/spec/requests/nonprofits/payments_controller_spec.rb +++ b/spec/requests/nonprofits/payments_controller_spec.rb @@ -1,13 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Nonprofits::PaymentsController, type: :request do - describe "#index" do - let(:user) { create(:user_as_nonprofit_associate) } + let(:user) { create(:user_as_nonprofit_associate) } let(:nonprofit) { user.roles.first.host } - - it 'loads properly' do + + it "loads properly" do sign_in user get "/nonprofits/#{nonprofit.id}/payments" diff --git a/spec/requests/nonprofits/supporters_spec.rb b/spec/requests/nonprofits/supporters_spec.rb index 2ae8050eb..a52e50bf9 100644 --- a/spec/requests/nonprofits/supporters_spec.rb +++ b/spec/requests/nonprofits/supporters_spec.rb @@ -1,34 +1,31 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe Nonprofits::SupportersController, type: :request do - - - describe 'throttling' do - let!(:nonprofit) { create(:nonprofit_base)} + describe "throttling" do + let!(:nonprofit) { create(:nonprofit_base) } before(:each) do - stub_const('FORCE_THROTTLE', true) + stub_const("FORCE_THROTTLE", true) end - it 'test number of supporter throttle' do + it "test number of supporter throttle" do 11.times { - post "/nonprofits/#{nonprofit.id}/supporters", params: {email: 'email@i.com'}.to_json, headers:{"CONTENT_TYPE" => "application/json" } - + post "/nonprofits/#{nonprofit.id}/supporters", params: {email: "email@i.com"}.to_json, headers: {"CONTENT_TYPE" => "application/json"} } assert_response 429 Timecop.freeze(61) do - post "/nonprofits/#{nonprofit.id}/supporters", params: {email: 'email@i.com'}.to_json, headers:{"CONTENT_TYPE" => "application/json" } + post "/nonprofits/#{nonprofit.id}/supporters", params: {email: "email@i.com"}.to_json, headers: {"CONTENT_TYPE" => "application/json"} expect(@response.status).to_not eq 429 end - end end - describe 'POST /sepa' do + describe "POST /sepa" do let!(:nonprofit) { Nonprofit.create(name: "new", city: "NY", state_code: "NY") } let(:supporter) { Supporter.create(nonprofit: nonprofit) } - let(:valid_params) do { + let(:valid_params) do + { supporter_id: supporter.id, sepa_params: { iban: "iban", @@ -38,22 +35,22 @@ } end - describe 'requires params' do - it 'is valid when sepa_params, donation_id and supporter_id are present' do + describe "requires params" do + it "is valid when sepa_params, donation_id and supporter_id are present" do post "/sepa", params: valid_params assert_response 200 assert_equal nil, JSON.parse(@response.body)["errors"] end - it 'is not valid without sepa_params' do + it "is not valid without sepa_params" do post "/sepa", params: valid_params.except(:sepa_params) assert_response 422 assert_equal ["sepa_params required"], JSON.parse(@response.body)["errors"] end - it 'is not valid without supporter_id' do + it "is not valid without supporter_id" do post "/sepa", params: valid_params.except(:supporter_id) assert_response 422 diff --git a/spec/requests/nonprofits_spec.rb b/spec/requests/nonprofits_spec.rb index 5ffcdde84..50f3e9dca 100644 --- a/spec/requests/nonprofits_spec.rb +++ b/spec/requests/nonprofits_spec.rb @@ -1,24 +1,24 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe NonprofitsController, type: :request do - let(:nonprofit) { create(:nonprofit_base, :with_default_billing_subscription)} - let(:user) { create(:user_as_nonprofit_associate, nonprofit: nonprofit) } + let(:nonprofit) { create(:nonprofit_base, :with_default_billing_subscription) } + let(:user) { create(:user_as_nonprofit_associate, nonprofit: nonprofit) } # without this, the nonprofit's pages for payments won't load properly - let!(:current_fee_era) { create(:fee_era_with_no_end)} + let!(:current_fee_era) { create(:fee_era_with_no_end) } - describe '#show' do + describe "#show" do before(:each) do nonprofit.update(published: true) # if we don't, the nonprofit is not visitable unless logged in end - it 'loads properly' do + it "loads properly" do get "/nonprofits/#{nonprofit.id}" expect(response).to have_http_status(:success) end end - describe '#dashboard' do - it 'loads properly' do + describe "#dashboard" do + it "loads properly" do sign_in user get "/nonprofits/#{nonprofit.id}/dashboard" expect(response).to have_http_status(:success) @@ -26,43 +26,42 @@ end describe "#dashboard_metrics" do - it 'loads properly' do + it "loads properly" do sign_in user get "/nonprofits/#{nonprofit.id}/dashboard_metrics", params: {format: :json} expect(response).to have_http_status(:success) end end - describe '#donate' do - it 'allows being put into a frame by not setting X-Frame-Options header' do + describe "#donate" do + it "allows being put into a frame by not setting X-Frame-Options header" do get "/nonprofits/#{nonprofit.id}/donate" expect(response).to have_http_status(:success) - expect(response.headers).to_not include 'X-Frame-Options' + expect(response.headers).to_not include "X-Frame-Options" end end - describe '#btn' do - it 'allows being put into a frame by not setting X-Frame-Options header' do + describe "#btn" do + it "allows being put into a frame by not setting X-Frame-Options header" do get "/nonprofits/#{nonprofit.id}/btn" expect(response).to have_http_status(:success) - expect(response.headers).to_not include 'X-Frame-Options' + expect(response.headers).to_not include "X-Frame-Options" end end - - describe '#profile_todos' do + describe "#profile_todos" do context "not logged in" do - it 'is unauthorized' do + it "is unauthorized" do get "/nonprofits/#{nonprofit.id}/profile_todos" expect(response).to have_http_status 302 end end - - context 'logged in' do - before(:each) { sign_in user} - it 'returns the proper json' do + + context "logged in" do + before(:each) { sign_in user } + it "returns the proper json" do get "/nonprofits/#{nonprofit.id}/profile_todos" - expect(JSON::parse(response.body)).to eq({ + expect(JSON.parse(response.body)).to eq({ "has_logo" => false, "has_background" => false, "has_summary" => false, @@ -73,4 +72,4 @@ end end end -end \ No newline at end of file +end diff --git a/spec/requests/users/sessions_controller_request_spec.rb b/spec/requests/users/sessions_controller_request_spec.rb index 9572bcdf5..1b68353f7 100644 --- a/spec/requests/users/sessions_controller_request_spec.rb +++ b/spec/requests/users/sessions_controller_request_spec.rb @@ -2,23 +2,22 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" RSpec.describe Users::SessionsController, type: :request do - it 'has X-Frame-Options=SAMEORIGIN set' do - get '/users/sign_in' + it "has X-Frame-Options=SAMEORIGIN set" do + get "/users/sign_in" - expect(response.headers['X-Frame-Options']).to eq 'SAMEORIGIN' + expect(response.headers["X-Frame-Options"]).to eq "SAMEORIGIN" end - it 'will lock out on the 11th attempt', skip: "spec does not work for some reason but does work in reality" do + it "will lock out on the 11th attempt", skip: "spec does not work for some reason but does work in reality" do user = create(:user) user.lock_access! 10.times do - post '/users/sign_in.json', params: {email: user.email, password: "not correct"} + post "/users/sign_in.json", params: {email: user.email, password: "not correct"} end @response = nil - post '/users/sign_in.json', params: {email: user.email, password: user.password} - + post "/users/sign_in.json", params: {email: user.email, password: user.password} end -end \ No newline at end of file +end diff --git a/spec/routing/slugged_nonprofits_spec.rb b/spec/routing/slugged_nonprofits_spec.rb index 93c72d9fe..8a8cd5f43 100644 --- a/spec/routing/slugged_nonprofits_spec.rb +++ b/spec/routing/slugged_nonprofits_spec.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" describe "Slugged routes", type: :routing do before(:each) do @@ -8,51 +8,51 @@ end describe "slugged_nonprofit" do - it 'routes to a nonprofit' do + it "routes to a nonprofit" do nonprofit = create(:nonprofit_base) expect(get: slugged_nonprofit_path(nonprofit)).to route_to( controller: "nonprofits", - action: "show", + action: "show", state_code: nonprofit.state_code_slug, city: nonprofit.city_slug, - name: nonprofit.slug, + name: nonprofit.slug ) end - it 'routes to a nonprofit and accepts params' do + it "routes to a nonprofit and accepts params" do nonprofit = create(:nonprofit_base) - expect(get: slugged_nonprofit_path(nonprofit, foo: 'bar')).to route_to( + expect(get: slugged_nonprofit_path(nonprofit, foo: "bar")).to route_to( controller: "nonprofits", - action: "show", + action: "show", state_code: nonprofit.state_code_slug, city: nonprofit.city_slug, name: nonprofit.slug, - foo: 'bar', + foo: "bar" ) end end describe "slugged_nonprofit_dashboard" do - it 'routes to a nonprofit dashboard' do + it "routes to a nonprofit dashboard" do nonprofit = create(:nonprofit_base) expect(get: slugged_nonprofit_dashboard_path(nonprofit)).to route_to( controller: "nonprofits", - action: "dashboard", + action: "dashboard", state_code: nonprofit.state_code_slug, city: nonprofit.city_slug, - name: nonprofit.slug, + name: nonprofit.slug ) end - it 'routes to a nonprofit dashboard and accepts params' do + it "routes to a nonprofit dashboard and accepts params" do nonprofit = create(:nonprofit_base) - expect(get: slugged_nonprofit_dashboard_path(nonprofit, foo: 'bar')).to route_to( + expect(get: slugged_nonprofit_dashboard_path(nonprofit, foo: "bar")).to route_to( controller: "nonprofits", - action: "dashboard", + action: "dashboard", state_code: nonprofit.state_code_slug, city: nonprofit.city_slug, name: nonprofit.slug, - foo: 'bar', + foo: "bar" ) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5d1179730..74e44588c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,9 +18,8 @@ # # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -require 'support/expect' -require 'support/mock_helpers' - +require "support/expect" +require "support/mock_helpers" include Expect # did a value change? no? then expectation passes @@ -59,63 +58,60 @@ # triggering implicit auto-inclusion in groups with matching metadata. config.shared_context_metadata_behavior = :apply_to_host_groups -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # This allows you to limit a spec run to individual examples or groups - # you care about by tagging them with `:focus` metadata. When nothing - # is tagged with `:focus`, all examples get run. RSpec also provides - # aliases for `it`, `describe`, and `context` that include `:focus` - # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - config.filter_run_when_matching :focus - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = 'doc' - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end - + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # This allows you to limit a spec run to individual examples or groups + # # you care about by tagging them with `:focus` metadata. When nothing + # # is tagged with `:focus`, all examples get run. RSpec also provides + # # aliases for `it`, `describe`, and `context` that include `:focus` + # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + # + # # Allows RSpec to persist some state between runs in order to support + # # the `--only-failures` and `--next-failure` CLI options. We recommend + # # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + # + # # Limits the available syntax to the non-monkey patched syntax that is + # # recommended. For more details, see: + # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + # config.disable_monkey_patching! + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = 'doc' + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed config.example_status_persistence_file_path = "tmp/failed-examples.txt" end if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9" module Kernel - alias :__at_exit :at_exit + alias_method :__at_exit, :at_exit def at_exit(&block) __at_exit do exit_status = $!.status if $!.is_a?(SystemExit) diff --git a/spec/support/construct.rb b/spec/support/construct.rb index 77856b208..ef09fbd49 100644 --- a/spec/support/construct.rb +++ b/spec/support/construct.rb @@ -1,14 +1,12 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class Construct < Struct + def self.new(hash) + keys = hash.keys + vals = hash.values + super(*keys).new(*vals) + end - def self.new(hash) - keys = hash.keys - vals = hash.values - return super(*keys).new(*vals) - end - - def expand(hash) - return Construct.new(self.to_h.merge(hash)) - end - + def expand(hash) + Construct.new(to_h.merge(hash)) + end end diff --git a/spec/support/contexts.rb b/spec/support/contexts.rb index 157cfa73f..3415eeb47 100644 --- a/spec/support/contexts.rb +++ b/spec/support/contexts.rb @@ -1,5 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -Dir["#{File.dirname (__FILE__)}/contexts/*"].each do |file| - require_relative "./contexts/#{File.basename(file, ".rb")}" +Dir["#{File.dirname(__FILE__)}/contexts/*"].each do |file| + require_relative "./contexts/#{File.basename(file, ".rb")}" end diff --git a/spec/support/contexts/as_money_context.rb b/spec/support/contexts/as_money_context.rb index cca1f626e..fbcab6fa3 100644 --- a/spec/support/contexts/as_money_context.rb +++ b/spec/support/contexts/as_money_context.rb @@ -3,10 +3,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -shared_examples 'an object with as_money attributes' do |*attributes| +shared_examples "an object with as_money attributes" do |*attributes| attributes.each do |attribute, amount| describe "for #{attribute}" do - before(:each) do + before(:each) do expect(subject).to receive(attribute.to_sym).and_return(1234) expect(subject).to receive(:currency).and_return("fake") end @@ -16,4 +16,4 @@ } end end -end \ No newline at end of file +end diff --git a/spec/support/contexts/calculated_names_context.rb b/spec/support/contexts/calculated_names_context.rb index 4f49ac9ae..730ca2247 100644 --- a/spec/support/contexts/calculated_names_context.rb +++ b/spec/support/contexts/calculated_names_context.rb @@ -2,64 +2,63 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" # rubocop:disable RSpec/VerifiedDoubles, RSpec/MessageSpies regular doubles work fine in this use-case -RSpec.shared_examples 'a model with a calculated first and last name' do - +RSpec.shared_examples "a model with a calculated first and last name" do let(:instance) { subject } - describe "#calculated_first_name" do - it "has nil name" do - instance.name = nil - expect(instance.calculated_first_name).to be_nil - end + describe "#calculated_first_name" do + it "has nil name" do + instance.name = nil + expect(instance.calculated_first_name).to be_nil + end - it "has blank name" do - instance.name = "" - expect(instance.calculated_first_name).to be_nil - end + it "has blank name" do + instance.name = "" + expect(instance.calculated_first_name).to be_nil + end - it "has one word name" do - instance.name = "Penelope" - expect(instance.calculated_first_name).to eq "Penelope" - end + it "has one word name" do + instance.name = "Penelope" + expect(instance.calculated_first_name).to eq "Penelope" + end - it "has two word name" do - instance.name = "Penelope Schultz" - expect(instance.calculated_first_name).to eq "Penelope" - end + it "has two word name" do + instance.name = "Penelope Schultz" + expect(instance.calculated_first_name).to eq "Penelope" + end - it "has three word name" do - instance.name = "Penelope Rebecca Schultz" - expect(instance.calculated_first_name).to eq "Penelope Rebecca" - end - end + it "has three word name" do + instance.name = "Penelope Rebecca Schultz" + expect(instance.calculated_first_name).to eq "Penelope Rebecca" + end + end - describe "#calculated_last_name" do - it "has nil name" do - instance.name = nil - expect(instance.calculated_last_name).to be_nil - end + describe "#calculated_last_name" do + it "has nil name" do + instance.name = nil + expect(instance.calculated_last_name).to be_nil + end - it "has blank name" do - instance.name = "" - expect(instance.calculated_last_name).to be_nil - end + it "has blank name" do + instance.name = "" + expect(instance.calculated_last_name).to be_nil + end - it "has one word name" do - instance.name = "Penelope" - expect(instance.calculated_last_name).to be_nil - end + it "has one word name" do + instance.name = "Penelope" + expect(instance.calculated_last_name).to be_nil + end - it "has two word name" do - instance.name = "Penelope Schultz" - expect(instance.calculated_last_name).to eq "Schultz" - end + it "has two word name" do + instance.name = "Penelope Schultz" + expect(instance.calculated_last_name).to eq "Schultz" + end - it "has three word name" do - instance.name = "Penelope Rebecca Schultz" - expect(instance.calculated_last_name).to eq "Schultz" - end - end + it "has three word name" do + instance.name = "Penelope Rebecca Schultz" + expect(instance.calculated_last_name).to eq "Schultz" + end + end end diff --git a/spec/support/contexts/charge_context.rb b/spec/support/contexts/charge_context.rb index 81e559e53..0d628f6ad 100644 --- a/spec/support/contexts/charge_context.rb +++ b/spec/support/contexts/charge_context.rb @@ -6,18 +6,14 @@ end let(:json) do - event_json['data']['object'] + event_json["data"]["object"] end - - end - -RSpec.shared_context :charge_succeeded_context do - include_context :charge_context do - - let(:event_json) do - event_json = StripeMockHelper.mock_webhook_event('charge.succeeded') +RSpec.shared_context :charge_succeeded_context do + include_context :charge_context do + let(:event_json) do + event_json = StripeMockHelper.mock_webhook_event("charge.succeeded") event_json end end @@ -26,8 +22,7 @@ RSpec.shared_context :charge_succeeded_specs do include_context :charge_succeeded_context - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end end - diff --git a/spec/support/contexts/common_fee_scenarios.rb b/spec/support/contexts/common_fee_scenarios.rb index 26e545839..3ecb95093 100644 --- a/spec/support/contexts/common_fee_scenarios.rb +++ b/spec/support/contexts/common_fee_scenarios.rb @@ -3,89 +3,39 @@ include_context :shared_donation_charge_context in_past = [{ - amount:10000, - source: :visa_card, + amount: 10000, + source: :visa_card, at: :in_past, calculate_fee_result: 505, calculate_stripe_fee_result: 250, refunds: [ { - desc: "Full", - refunded_already: 0, + desc: "Full", + refunded_already: 0, application_fee_refunded_already: 0, amount_refunded: 10000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 505 }, { - desc: "half", - refunded_already: 5000, + desc: "half", + refunded_already: 5000, application_fee_refunded_already: 0, amount_refunded: 5000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505)/2 - }, - { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 151 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 504, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 505, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, - { - amount:10000, - source: :uk_visa_card, - at: :in_past, - calculate_fee_result: 505, - calculate_stripe_fee_result: 250, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505 + calculate_application_fee_refund_result: 505 / 2 }, { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505)/2 - }, - { desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, + refunded_already: 0, application_fee_refunded_already: 195, - amount_refunded:3000, + amount_refunded: 3000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 151 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, + refunded_already: 500, application_fee_refunded_already: 504, amount_refunded: 50, charge_marked_as_refunded: true, @@ -93,557 +43,657 @@ }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, + refunded_already: 9999, application_fee_refunded_already: 505, amount_refunded: 1, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 0 } - + ] }, - { - amount:10000, - source: :amex_card, - at: :in_past, - calculate_fee_result: 505, - calculate_stripe_fee_result: 250, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505)/2 - }, + { + amount: 10000, + source: :uk_visa_card, + at: :in_past, + calculate_fee_result: 505, + calculate_stripe_fee_result: 250, + refunds: [ { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 151 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 504, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 505, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, - - { - amount:10000, - source: :amex_card, - at: :in_past, - calculate_fee_result: 505, - calculate_stripe_fee_result: 250, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505)/2 - }, + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 + }, { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 151 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 504, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 505, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, - { - amount:10000, - source: :source_from_ru, - at: :in_past, - calculate_fee_result: 505, - calculate_stripe_fee_result: 250, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505)/2 - }, + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 / 2 + }, { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 151 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 504, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 505, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, - { - amount:10000, - source: :discover_card, - at: :in_past, - calculate_fee_result: 505, - calculate_stripe_fee_result: 250, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505)/2 - }, + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 151 + }, { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 151 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 504, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 505, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, -] - -now = -#Current era both passed and unpassed -[:now, nil].map{|time| + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 504, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 505, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } -[{ -amount:10000, -source: :visa_card, -at: time, -calculate_fee_result: 580, -calculate_stripe_fee_result: 325, -refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 580-325 - }, + ] + }, + { + amount: 10000, + source: :amex_card, + at: :in_past, + calculate_fee_result: 505, + calculate_stripe_fee_result: 250, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 151 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 504, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 505, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (580-325)/2 - }, - { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 254, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } -] -}, -{ -amount:10000, -source: :uk_visa_card, -at: time, -calculate_fee_result: 680, -calculate_stripe_fee_result: 425, -refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 680-425 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (680-425)/2 - }, - { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 254, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } -] -}, -{ -amount:10000, -source: :source_from_ru, -at: time, -calculate_fee_result: 605, -calculate_stripe_fee_result: 350, -refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 605-350 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (605-350)/2 - }, - { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 254, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } -] -}, + ] + }, -{ -amount:10000, -source: :amex_card, -at: time, -calculate_fee_result: 705, -calculate_stripe_fee_result: 450, -refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 705-450 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (705-450)/2 - }, { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 254, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } + amount: 10000, + source: :amex_card, + at: :in_past, + calculate_fee_result: 505, + calculate_stripe_fee_result: 250, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 151 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 504, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 505, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } -] -}, + ] + }, + { + amount: 10000, + source: :source_from_ru, + at: :in_past, + calculate_fee_result: 505, + calculate_stripe_fee_result: 250, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 151 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 504, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 505, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } -{ -amount:10000, -source: :amex_card, -at: time, -calculate_fee_result: 705, -calculate_stripe_fee_result: 450, -refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 705-450 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (705-450)/2 - }, + ] + }, { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 254, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } + amount: 10000, + source: :discover_card, + at: :in_past, + calculate_fee_result: 505, + calculate_stripe_fee_result: 250, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 151 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 504, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 505, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } -] -}, + ] + }] -{ - amount:10000, - source: :source_from_ru, - at: time, - calculate_fee_result: 605, - calculate_stripe_fee_result: 350, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 605-350 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (605-350)/2 + now = + # Current era both passed and unpassed + [:now, nil].map { |time| + [{ + amount: 10000, + source: :visa_card, + at: time, + calculate_fee_result: 580, + calculate_stripe_fee_result: 325, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 580 - 325 + }, + + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (580 - 325) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 254, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + ] }, { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 255-1, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, - { - amount:10000, - source: :discover_card, - at: time, + amount: 10000, + source: :uk_visa_card, + at: time, + calculate_fee_result: 680, + calculate_stripe_fee_result: 425, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 680 - 425 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (680 - 425) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 254, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + ] + }, + { + amount: 10000, + source: :source_from_ru, + at: time, + calculate_fee_result: 605, + calculate_stripe_fee_result: 350, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 605 - 350 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (605 - 350) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 254, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + ] + }, + + { + amount: 10000, + source: :amex_card, + at: time, + calculate_fee_result: 705, + calculate_stripe_fee_result: 450, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 705 - 450 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (705 - 450) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 254, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + + ] + }, + + { + amount: 10000, + source: :amex_card, + at: time, + calculate_fee_result: 705, + calculate_stripe_fee_result: 450, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 705 - 450 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (705 - 450) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 254, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + + ] + }, + + { + amount: 10000, + source: :source_from_ru, + at: time, + calculate_fee_result: 605, + calculate_stripe_fee_result: 350, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 605 - 350 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (605 - 350) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 255 - 1, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + + ] + }, + { + amount: 10000, + source: :discover_card, + at: time, + calculate_fee_result: 505, + calculate_stripe_fee_result: 250, + refunds: [ + { + desc: "Full", + refunded_already: 0, + application_fee_refunded_already: 0, + amount_refunded: 10000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 505 - 250 + }, + { + desc: "half", + refunded_already: 5000, + application_fee_refunded_already: 0, + amount_refunded: 5000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: (505 - 250) / 2 + }, + { + desc: "partial_refund_when_part_already_refunded", + refunded_already: 0, + application_fee_refunded_already: 195, + amount_refunded: 3000, + charge_marked_as_refunded: false, + calculate_application_fee_refund_result: 60 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 500, + application_fee_refunded_already: 254, + amount_refunded: 50, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 1 + }, + { + desc: "partial_refund_finishing_off_partial_refund", + refunded_already: 9999, + application_fee_refunded_already: 255, + amount_refunded: 1, + charge_marked_as_refunded: true, + calculate_application_fee_refund_result: 0 + } + + ] + }] + }.flatten + + in_future = [{ + amount: 10000, + source: :visa_card, + at: :in_future, calculate_fee_result: 505, calculate_stripe_fee_result: 250, refunds: [ { - desc: "Full", - refunded_already: 0, + desc: "Full", + refunded_already: 0, application_fee_refunded_already: 0, amount_refunded: 10000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505-250 + calculate_application_fee_refund_result: 505 - 250 }, { - desc: "half", - refunded_already: 5000, + desc: "half", + refunded_already: 5000, application_fee_refunded_already: 0, amount_refunded: 5000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505-250)/2 + calculate_application_fee_refund_result: (505 - 250) / 2 }, - { + { desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, + refunded_already: 0, application_fee_refunded_already: 195, - amount_refunded:3000, + amount_refunded: 3000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 60 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, + refunded_already: 500, application_fee_refunded_already: 254, amount_refunded: 50, charge_marked_as_refunded: true, @@ -651,52 +701,50 @@ }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, + refunded_already: 9999, application_fee_refunded_already: 255, amount_refunded: 1, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 0 } - + ] }, - -]}.flatten - -in_future = [{ - amount:10000, - source: :visa_card, - at: :in_future, - calculate_fee_result: 505, - calculate_stripe_fee_result: 250, + { + amount: 10000, + source: :uk_visa_card, + at: :in_future, + calculate_fee_result: 605, + calculate_stripe_fee_result: 350, refunds: [ { - desc: "Full", - refunded_already: 0, + desc: "Full", + refunded_already: 0, + fee_refunded_already: 0, application_fee_refunded_already: 0, amount_refunded: 10000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505-250 + calculate_application_fee_refund_result: 605 - 350 }, { - desc: "half", - refunded_already: 5000, + desc: "half", + refunded_already: 5000, application_fee_refunded_already: 0, amount_refunded: 5000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505-250)/2 + calculate_application_fee_refund_result: (605 - 350) / 2 }, - { + { desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, + refunded_already: 0, application_fee_refunded_already: 195, - amount_refunded:3000, + amount_refunded: 3000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 60 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, + refunded_already: 500, application_fee_refunded_already: 254, amount_refunded: 50, charge_marked_as_refunded: true, @@ -704,50 +752,50 @@ }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, + refunded_already: 9999, application_fee_refunded_already: 255, amount_refunded: 1, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 0 } - + ] - }, - { - amount:10000, - source: :uk_visa_card, + }, + + { + amount: 10000, + source: :amex_card, at: :in_future, - calculate_fee_result: 605, - calculate_stripe_fee_result: 350, + calculate_fee_result: 705, + calculate_stripe_fee_result: 450, refunds: [ { - desc: "Full", - refunded_already: 0, - fee_refunded_already: 0, + desc: "Full", + refunded_already: 0, application_fee_refunded_already: 0, amount_refunded: 10000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 605-350 + calculate_application_fee_refund_result: 705 - 450 }, { - desc: "half", - refunded_already: 5000, + desc: "half", + refunded_already: 5000, application_fee_refunded_already: 0, amount_refunded: 5000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (605-350)/2 + calculate_application_fee_refund_result: (705 - 450) / 2 }, - { + { desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, + refunded_already: 0, application_fee_refunded_already: 195, - amount_refunded:3000, + amount_refunded: 3000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 60 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, + refunded_already: 500, application_fee_refunded_already: 254, amount_refunded: 50, charge_marked_as_refunded: true, @@ -755,151 +803,100 @@ }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, + refunded_already: 9999, application_fee_refunded_already: 255, amount_refunded: 1, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 0 } - + ] - }, - - { - amount:10000, - source: :amex_card, - at: :in_future, - calculate_fee_result: 705, - calculate_stripe_fee_result: 450, - refunds: [ - { - desc: "Full", - refunded_already: 0, - application_fee_refunded_already: 0, - amount_refunded: 10000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 705-450 - }, - { - desc: "half", - refunded_already: 5000, - application_fee_refunded_already: 0, - amount_refunded: 5000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (705-450)/2 - }, - { - desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, - application_fee_refunded_already: 195, - amount_refunded:3000, - charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 60 - }, - { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 254, - amount_refunded: 50, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 1 }, + { - desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, - application_fee_refunded_already: 255, - amount_refunded: 1, - charge_marked_as_refunded: true, - calculate_application_fee_refund_result: 0 - } - - ] - }, - - { - amount:10000, - source: :source_from_ru, + amount: 10000, + source: :source_from_ru, at: :in_future, calculate_fee_result: 605, calculate_stripe_fee_result: 350, refunds: [ { - desc: "Full", - refunded_already: 0, + desc: "Full", + refunded_already: 0, application_fee_refunded_already: 0, amount_refunded: 10000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 605-350 + calculate_application_fee_refund_result: 605 - 350 }, { - desc: "half", - refunded_already: 5000, + desc: "half", + refunded_already: 5000, application_fee_refunded_already: 0, amount_refunded: 5000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (605-350)/2 + calculate_application_fee_refund_result: (605 - 350) / 2 }, - { + { desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, + refunded_already: 0, application_fee_refunded_already: 195, - amount_refunded:3000, + amount_refunded: 3000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 60 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, - application_fee_refunded_already: 255-1, + refunded_already: 500, + application_fee_refunded_already: 255 - 1, amount_refunded: 50, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 1 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, + refunded_already: 9999, application_fee_refunded_already: 255, amount_refunded: 1, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 0 } - + ] }, { - amount:10000, - source: :discover_card, + amount: 10000, + source: :discover_card, at: :in_future, calculate_fee_result: 505, calculate_stripe_fee_result: 250, refunds: [ { - desc: "Full", - refunded_already: 0, + desc: "Full", + refunded_already: 0, application_fee_refunded_already: 0, amount_refunded: 10000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: 505-250 + calculate_application_fee_refund_result: 505 - 250 }, { - desc: "half", - refunded_already: 5000, + desc: "half", + refunded_already: 5000, application_fee_refunded_already: 0, amount_refunded: 5000, charge_marked_as_refunded: false, - calculate_application_fee_refund_result: (505-250)/2 + calculate_application_fee_refund_result: (505 - 250) / 2 }, - { + { desc: "partial_refund_when_part_already_refunded", - refunded_already: 0, + refunded_already: 0, application_fee_refunded_already: 195, - amount_refunded:3000, + amount_refunded: 3000, charge_marked_as_refunded: false, calculate_application_fee_refund_result: 60 }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 500, + refunded_already: 500, application_fee_refunded_already: 254, amount_refunded: 50, charge_marked_as_refunded: true, @@ -907,26 +904,23 @@ }, { desc: "partial_refund_finishing_off_partial_refund", - refunded_already: 9999, + refunded_already: 9999, application_fee_refunded_already: 255, amount_refunded: 1, charge_marked_as_refunded: true, calculate_application_fee_refund_result: 0 } - - ] - }, - - ] + ] + }] SCENARIOS ||= [].concat(in_past).concat(now).concat(in_future) - + def get_source(example_details) eval(example_details[:source].to_s) end - def at(example_details) + def at(example_details) case example_details[:at] when :now Time.current @@ -934,8 +928,6 @@ def at(example_details) Time.new(2000, 1, 1) when :in_future Time.new(2022, 1, 1) - else - nil end end end diff --git a/spec/support/contexts/disputes_context.rb b/spec/support/contexts/disputes_context.rb index ce089c4f5..095c3e8dc 100644 --- a/spec/support/contexts/disputes_context.rb +++ b/spec/support/contexts/disputes_context.rb @@ -5,67 +5,66 @@ end end - let(:nonprofit) { force_create(:nonprofit)} - let(:supporter) { force_create(:supporter, nonprofit: nonprofit)} + let(:nonprofit) { force_create(:nonprofit) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit) } let(:json) do - event_json['data']['object'] + event_json["data"]["object"] end - let(:dispute_created_time) { Time.at(1596429790)} - let(:dispute_created_time__partial1) {dispute_created_time} - - let(:dispute_withdrawal_payment_time) { Time.at( 1596430500 )} - let(:dispute_withdrawal_payment_time__partial1) {dispute_withdrawal_payment_time} + let(:dispute_created_time) { Time.at(1596429790) } + let(:dispute_created_time__partial1) { dispute_created_time } - let(:dispute_created__partial2) {Time.at( 1596430600 )} + let(:dispute_withdrawal_payment_time) { Time.at(1596430500) } + let(:dispute_withdrawal_payment_time__partial1) { dispute_withdrawal_payment_time } - let(:dispute_withdrawal_payment_time__partial2) {Time.at( 1596430650 )} + let(:dispute_created__partial2) { Time.at(1596430600) } - let(:dispute_reinstatement_payment_time) { Time.at( 1596432510)} + let(:dispute_withdrawal_payment_time__partial2) { Time.at(1596430650) } + + let(:dispute_reinstatement_payment_time) { Time.at(1596432510) } let(:dispute) { obj.dispute } let(:dispute_transactions) { dispute.dispute_transactions } # we reload this because we'll get the older version if we don't - let(:original_payment) { + let(:original_payment) { obj.dispute.original_payment.reload obj.dispute.original_payment - } - let(:withdrawal_transaction) {dispute.dispute_transactions.order("date").first} - let(:withdrawal_payment) {withdrawal_transaction.payment} - let(:reinstated_transaction) {dispute.dispute_transactions.order("date").second} - let(:reinstated_payment) {reinstated_transaction.payment} + let(:withdrawal_transaction) { dispute.dispute_transactions.order("date").first } + let(:withdrawal_payment) { withdrawal_transaction.payment } + let(:reinstated_transaction) { dispute.dispute_transactions.order("date").second } + let(:reinstated_payment) { reinstated_transaction.payment } end RSpec.shared_context :disputes_specs do before(:each) do allow(JobQueue).to receive(:queue) end - + all_events = [:created, :updated, :funds_reinstated, :funds_withdrawn, :won, :lost] - - it 'has correct events in order' do + it "has correct events in order" do valid_events.each do |t| - - job_type = ('JobTypes::Dispute' + t.to_s.camelize + "Job").constantize + job_type = ("JobTypes::Dispute" + t.to_s.camelize + "Job").constantize expect(JobQueue).to have_received(:queue).with( - job_type, dispute).ordered + job_type, dispute + ).ordered end end - it 'does not have invalid events' do + it "does not have invalid events" do invalid_events = all_events - valid_events invalid_events.each do |t| - job_type = ('JobTypes::Dispute' + t.to_s.camelize + "Job").constantize + job_type = ("JobTypes::Dispute" + t.to_s.camelize + "Job").constantize expect(JobQueue).to_not have_received(:queue).with( - job_type) + job_type + ) end end - it 'has valid activities' do + it "has valid activities" do valid_events.each do |t| dispute_kind = "Dispute" + t.to_s.camelize case t @@ -79,41 +78,42 @@ end end - it 'does not have invalid activities' do + it "does not have invalid activities" do invalid_events = all_events - valid_events invalid_events.each do |t| dispute_kind = "Dispute" + t.to_s.camelize case t when :funds_withdrawn - if (withdrawal_transaction) + if withdrawal_transaction expect(withdrawal_transaction.payment.activities.where(kind: dispute_kind)).to be_empty, "#{dispute_kind} should not have been here." end when :funds_reinstated - if (reinstated_transaction) + if reinstated_transaction expect(reinstated_transaction.payment.activities.where(kind: dispute_kind)).to be_empty, "#{dispute_kind} should not have been here." end else - #byebug if dispute_kind == "DisputeUpdated" && dispute.activities.where(kind: dispute_kind).any? + # byebug if dispute_kind == "DisputeUpdated" && dispute.activities.where(kind: dispute_kind).any? expect(dispute.activities.where(kind: dispute_kind)).to be_empty, "#{dispute_kind} should not have been here." end end end end -RSpec.shared_context :dispute_created_context do - include_context :disputes_context do - - let(:event_json) do - event_json = StripeMockHelper.mock_webhook_event('charge.dispute.created') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json['data']['object']) +RSpec.shared_context :dispute_created_context do + include_context :disputes_context do + let(:event_json) do + event_json = StripeMockHelper.mock_webhook_event("charge.dispute.created") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json["data"]["object"]) event_json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end end @@ -121,82 +121,82 @@ include_context :dispute_created_context include_context :disputes_specs - it 'has status of needs_response' do - expect(obj.status).to eq 'needs_response' + it "has status of needs_response" do + expect(obj.status).to eq "needs_response" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 0 balance transactions' do + it "has 0 balance transactions" do expect(obj.balance_transactions.count).to eq 0 end - it 'has a net_change of 0' do + it "has a net_change of 0" do expect(obj.net_change).to eq 0 end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end - it 'has a saved dispute' do + it "has a saved dispute" do expect(dispute).to be_persisted end - it 'has a dispute with 80000' do + it "has a dispute with 80000" do expect(dispute.gross_amount).to eq 80000 end - it 'has a dispute with status of needs_response' do + it "has a dispute with status of needs_response" do expect(dispute.status).to eq "needs_response" end - it 'has a dispute with reason of duplicate' do - expect(dispute.reason).to eq 'duplicate' + it "has a dispute with reason of duplicate" do + expect(dispute.reason).to eq "duplicate" end - it 'has a dispute with started_at of dispute_created_time' do + it "has a dispute with started_at of dispute_created_time" do expect(dispute.started_at).to eq dispute_created_time end - it 'has no dispute transactions' do + it "has no dispute transactions" do expect(dispute_transactions).to eq [] end specify { expect(original_payment.refund_total).to eq 0 } - let(:valid_events) { [:created]} + let(:valid_events) { [:created] } end -RSpec.shared_context :dispute_funds_withdrawn_context do - include_context :disputes_context do - - let(:event_json) do - event_json = StripeMockHelper.mock_webhook_event('charge.dispute.funds_withdrawn') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json['data']['object']) +RSpec.shared_context :dispute_funds_withdrawn_context do + include_context :disputes_context do + let(:event_json) do + event_json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_withdrawn") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json["data"]["object"]) event_json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} - + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end end @@ -204,125 +204,127 @@ include_context :dispute_funds_withdrawn_context include_context :disputes_specs - it 'has status of needs_response' do - expect(obj.status).to eq 'needs_response' + it "has status of needs_response" do + expect(obj.status).to eq "needs_response" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end describe "dispute" do subject { dispute } - specify {expect(subject).to be_persisted } - specify {expect(subject.gross_amount).to eq 80000 } - specify {expect(subject.status).to eq "needs_response" } - specify { expect(subject.reason).to eq 'duplicate' } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.status).to eq "needs_response" } + specify { expect(subject.reason).to eq "duplicate" } specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has one dispute transaction' do + it "has one dispute transaction" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject).to be_persisted } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject).to be_persisted } specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end specify { expect(original_payment.refund_total).to eq 80000 } - let(:valid_events) { [:created, :funds_withdrawn]} + let(:valid_events) { [:created, :funds_withdrawn] } end RSpec.shared_context :dispute_funds_reinstated_context do include_context :disputes_context let(:event_json) do - event_json =StripeMockHelper.mock_webhook_event('charge.dispute.funds_reinstated') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json['data']['object']) + event_json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_reinstated") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json["data"]["object"]) event_json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end RSpec.shared_context :dispute_funds_reinstated_specs do include_context :dispute_funds_reinstated_context include_context :disputes_specs - it 'has status of under_review' do - expect(obj.status).to eq 'under_review' + it "has status of under_review" do + expect(obj.status).to eq "under_review" end - it 'has reason of credit_not_processed' do - expect(obj.reason).to eq 'credit_not_processed' + it "has reason of credit_not_processed" do + expect(obj.reason).to eq "credit_not_processed" end - it 'has 0 balance transactions' do + it "has 0 balance transactions" do expect(obj.balance_transactions.count).to eq 2 end - it 'has a net_change of 0' do + it "has a net_change of 0" do expect(obj.net_change).to eq 0 end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end @@ -331,110 +333,111 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 80000 } specify { expect(subject.status).to eq "under_review" } - specify { expect(subject.reason).to eq 'credit_not_processed' } - specify { expect(subject.started_at).to eq dispute_created_time} + specify { expect(subject.reason).to eq "credit_not_processed" } + specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has two dispute transactions' do + it "has two dispute transactions" do expect(dispute_transactions.count).to eq 2 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y75JVBCJIIhvMWmsnGK1JLD' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y75JVBCJIIhvMWmsnGK1JLD" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } + end + + describe "has a reinstated_transaction" do + subject { reinstated_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} - end - - - describe 'has a reinstated_transaction' do - subject{ reinstated_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq 80000 } - specify { expect(subject.fee_total).to eq 1500 } - specify { expect(subject.net_amount).to eq 81500} - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y71X0BCJIIhvMWmMmtTY4m1' } - specify { expect(subject.date).to eq dispute_reinstatement_payment_time} + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.fee_total).to eq 1500 } + specify { expect(subject.net_amount).to eq 81500 } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y71X0BCJIIhvMWmMmtTY4m1" } + specify { expect(subject.date).to eq dispute_reinstatement_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a reinstated_payment' do - subject { reinstated_payment} + describe "has a reinstated_payment" do + subject { reinstated_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq 80000} - specify { expect(subject.fee_total).to eq 1500} - specify { expect(subject.kind).to eq 'DisputeReversed'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_reinstatement_payment_time} + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.fee_total).to eq 1500 } + specify { expect(subject.kind).to eq "DisputeReversed" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_reinstatement_payment_time } end specify { expect(original_payment.refund_total).to eq 0 } - let(:valid_events) { [:created, :funds_withdrawn, :funds_reinstated]} + let(:valid_events) { [:created, :funds_withdrawn, :funds_reinstated] } end RSpec.shared_context :dispute_lost_context do include_context :disputes_context let(:event_json) do - event_json =StripeMockHelper.mock_webhook_event('charge.dispute.closed-lost') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json['data']['object']) + event_json = StripeMockHelper.mock_webhook_event("charge.dispute.closed-lost") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json["data"]["object"]) event_json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end RSpec.shared_context :dispute_lost_specs do include_context :dispute_lost_context include_context :disputes_specs - it 'has status of under_review' do - expect(obj.status).to eq 'lost' + it "has status of under_review" do + expect(obj.status).to eq "lost" end - it 'has reason of credit_not_processed' do - expect(obj.reason).to eq 'duplicate' + it "has reason of credit_not_processed" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id' do + it "has a correct charge id" do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do - expect(obj.started_at).to eq dispute_created_time + it "has a started_at of dispute_created_time" do + expect(obj.started_at).to eq dispute_created_time end describe "dispute" do @@ -442,89 +445,91 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 80000 } specify { expect(subject.status).to eq "lost" } - specify { expect(subject.reason).to eq 'duplicate' } + specify { expect(subject.reason).to eq "duplicate" } specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has 1 dispute transactions' do + it "has 1 dispute transactions" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end - it 'has no reinstated transaction' do + it "has no reinstated transaction" do expect(reinstated_transaction).to be_nil end - let(:valid_events) { [:created, :funds_withdrawn, :lost]} + let(:valid_events) { [:created, :funds_withdrawn, :lost] } end RSpec.shared_context :dispute_won_context do include_context :disputes_context let(:event_json) do - event_json =StripeMockHelper.mock_webhook_event('charge.dispute.closed-won') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json['data']['object']) + event_json = StripeMockHelper.mock_webhook_event("charge.dispute.closed-won") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, event_json["data"]["object"]) event_json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end RSpec.shared_context :dispute_won_specs do include_context :dispute_won_context include_context :disputes_specs - it 'has status of won' do - expect(obj.status).to eq 'won' + it "has status of won" do + expect(obj.status).to eq "won" end - it 'has reason of credit_not_processed' do - expect(obj.reason).to eq 'credit_not_processed' + it "has reason of credit_not_processed" do + expect(obj.reason).to eq "credit_not_processed" end - it 'has 2 balance transactions' do + it "has 2 balance transactions" do expect(obj.balance_transactions.count).to eq 2 end - it 'has a net_change of 0' do + it "has a net_change of 0" do expect(obj.net_change).to eq 0 end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - - it 'has a started_at of dispute_created_time' do + + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end @@ -533,351 +538,354 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 80000 } specify { expect(subject.status).to eq "won" } - specify { expect(subject.reason).to eq 'credit_not_processed' } + specify { expect(subject.reason).to eq "credit_not_processed" } specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has two dispute transactions' do + it "has two dispute transactions" do expect(dispute_transactions.count).to eq 2 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y75JVBCJIIhvMWmsnGK1JLD' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y75JVBCJIIhvMWmsnGK1JLD" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } + end + + describe "has a reinstated_transaction" do + subject { reinstated_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500 } - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} - end - - - describe 'has a reinstated_transaction' do - subject{ reinstated_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq 80000 } - specify { expect(subject.fee_total).to eq 1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y71X0BCJIIhvMWmMmtTY4m1' } - specify { expect(subject.date).to eq dispute_reinstatement_payment_time} + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.fee_total).to eq 1500 } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y71X0BCJIIhvMWmMmtTY4m1" } + specify { expect(subject.date).to eq dispute_reinstatement_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a reinstated_payment' do - subject { reinstated_payment} + describe "has a reinstated_payment" do + subject { reinstated_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq 80000} - specify { expect(subject.fee_total).to eq 1500} + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.fee_total).to eq 1500 } specify { expect(subject.net_amount).to eq 81500 } - specify { expect(subject.kind).to eq 'DisputeReversed'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_reinstatement_payment_time} + specify { expect(subject.kind).to eq "DisputeReversed" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_reinstatement_payment_time } end specify { expect(original_payment.refund_total).to eq 0 } - let(:valid_events) { [:created, :funds_withdrawn, :funds_reinstated, :won]} + let(:valid_events) { [:created, :funds_withdrawn, :funds_reinstated, :won] } end -RSpec.shared_context :dispute_created_and_withdrawn_at_same_time_context do +RSpec.shared_context :dispute_created_and_withdrawn_at_same_time_context do include_context :disputes_context let(:event_json_created) do - StripeMockHelper.mock_webhook_event('charge.dispute.created-with-one-withdrawn') + StripeMockHelper.mock_webhook_event("charge.dispute.created-with-one-withdrawn") end - let(:json_created) { event_json_created['data']['object']} + let(:json_created) { event_json_created["data"]["object"] } - let(:json_funds_withdrawn) {event_json_funds_withdrawn['data']['object']} + let(:json_funds_withdrawn) { event_json_funds_withdrawn["data"]["object"] } let(:event_json_funds_withdrawn) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.funds_withdrawn') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_withdrawn") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end RSpec.shared_context :dispute_created_and_withdrawn_at_same_time_specs do include_context :dispute_created_and_withdrawn_at_same_time_context include_context :disputes_specs - it 'has status of needs_response' do - expect(obj.status).to eq 'needs_response' + it "has status of needs_response" do + expect(obj.status).to eq "needs_response" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end describe "dispute" do subject { dispute } - specify {expect(subject).to be_persisted } - specify {expect(subject.gross_amount).to eq 80000 } - specify {expect(subject.status).to eq "needs_response" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created_time} + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.status).to eq "needs_response" } + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has one dispute transaction' do + it "has one dispute transaction" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end - it 'has only added one payment' do + it "has only added one payment" do obj - expect(Payment.count).to eq 2 #one for charge, one for DisputeTransaction + expect(Payment.count).to eq 2 # one for charge, one for DisputeTransaction end - it 'has only one dispute transaction' do + it "has only one dispute transaction" do obj expect(DisputeTransaction.count).to eq 1 end specify { expect(original_payment.refund_total).to eq 80000 } - let(:valid_events) { [:created, :funds_withdrawn]} + let(:valid_events) { [:created, :funds_withdrawn] } end -RSpec.shared_context :dispute_created_and_withdrawn_in_order_context do +RSpec.shared_context :dispute_created_and_withdrawn_in_order_context do include_context :dispute_created_and_withdrawn_at_same_time_context let(:event_json_created) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.created") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let(:json_created) { event_json_created['data']['object']} + let(:json_created) { event_json_created["data"]["object"] } - let(:json_funds_withdrawn) {event_json_funds_withdrawn['data']['object']} + let(:json_funds_withdrawn) { event_json_funds_withdrawn["data"]["object"] } let(:event_json_funds_withdrawn) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.funds_withdrawn') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_withdrawn") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end RSpec.shared_context :dispute_created_and_withdrawn_in_order_specs do include_context :dispute_created_and_withdrawn_in_order_context include_context :disputes_specs - it 'has status of needs_response' do - expect(obj.status).to eq 'needs_response' + it "has status of needs_response" do + expect(obj.status).to eq "needs_response" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id ' do + it "has a correct charge id " do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end describe "dispute" do subject { dispute } - specify {expect(subject).to be_persisted } - specify {expect(subject.gross_amount).to eq 80000 } - specify {expect(subject.status).to eq "needs_response" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created_time} + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq 80000 } + specify { expect(subject.status).to eq "needs_response" } + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has one dispute transaction' do + it "has one dispute transaction" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } - specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject).to be_persisted } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } + specify { expect(subject).to be_persisted } + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject).to be_persisted } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end - it 'has only added one payment' do + it "has only added one payment" do obj - expect(Payment.count).to eq 2 #one for charge, one for DisputeTransaction + expect(Payment.count).to eq 2 # one for charge, one for DisputeTransaction end - it 'has only one dispute transaction' do + it "has only one dispute transaction" do obj expect(DisputeTransaction.count).to eq 1 end specify { expect(original_payment.refund_total).to eq 80000 } - let(:valid_events) { [:created, :funds_withdrawn]} + let(:valid_events) { [:created, :funds_withdrawn] } end -RSpec.shared_context :dispute_created_withdrawn_and_lost_in_order_context do +RSpec.shared_context :dispute_created_withdrawn_and_lost_in_order_context do include_context :disputes_context let(:event_json_created) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.created") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let(:json_created) { event_json_created['data']['object']} + let(:json_created) { event_json_created["data"]["object"] } let(:event_json_funds_withdrawn) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.funds_withdrawn') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_withdrawn") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let(:json_funds_withdrawn) {event_json_funds_withdrawn['data']['object']} + let(:json_funds_withdrawn) { event_json_funds_withdrawn["data"]["object"] } let(:event_json_lost) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.closed-lost') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.closed-lost") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - + let(:json_lost) do - event_json_lost['data']['object'] + event_json_lost["data"]["object"] end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } end -RSpec.shared_context :dispute_created_withdrawn_and_lost_in_order_specs do +RSpec.shared_context :dispute_created_withdrawn_and_lost_in_order_specs do include_context :dispute_created_withdrawn_and_lost_in_order_context include_context :disputes_specs - it 'has status of lost' do - expect(obj.status).to eq 'lost' + it "has status of lost" do + expect(obj.status).to eq "lost" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id' do + it "has a correct charge id" do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end @@ -886,51 +894,50 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 80000 } specify { expect(subject.status).to eq "lost" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created_time} + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has 1 dispute transactions' do + it "has 1 dispute transactions" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end - it 'has no reinstated transaction' do + it "has no reinstated transaction" do expect(reinstated_transaction).to be_nil end specify { expect(original_payment.refund_total).to eq 80000 } - let(:valid_events) { [:created, :funds_withdrawn, :lost]} + let(:valid_events) { [:created, :funds_withdrawn, :lost] } end RSpec.shared_context :dispute_created_with_withdrawn_and_lost_in_order_context do - include_context :dispute_created_withdrawn_and_lost_in_order_context let(:event_json_created) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created-with-one-withdrawn') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.created-with-one-withdrawn") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end end @@ -939,35 +946,35 @@ include_context :dispute_created_with_withdrawn_and_lost_in_order_context include_context :disputes_specs - it 'has status of lost' do - expect(obj.status).to eq 'lost' + it "has status of lost" do + expect(obj.status).to eq "lost" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id' do + it "has a correct charge id" do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end @@ -976,79 +983,80 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 80000 } specify { expect(subject.status).to eq "lost" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created_time} + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has 1 dispute transactions' do + it "has 1 dispute transactions" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end - it 'has no reinstated transaction' do + it "has no reinstated transaction" do expect(reinstated_transaction).to be_nil end specify { expect(original_payment.refund_total).to eq 80000 } - let(:valid_events) { [:created, :funds_withdrawn, :lost]} + let(:valid_events) { [:created, :funds_withdrawn, :lost] } end RSpec.shared_context :dispute_lost_created_and_funds_withdrawn_at_same_time_context do - include_context :disputes_context let(:event_json_created) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created') + json = StripeMockHelper.mock_webhook_event("charge.dispute.created") json end - let(:json_created) { event_json_created['data']['object']} + let(:json_created) { event_json_created["data"]["object"] } let(:event_json_funds_withdrawn) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.funds_withdrawn') + json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_withdrawn") json end - let(:json_funds_withdrawn) {event_json_funds_withdrawn['data']['object']} + let(:json_funds_withdrawn) { event_json_funds_withdrawn["data"]["object"] } let(:event_json_lost) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.closed-lost') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.closed-lost") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - + let(:json_lost) do - event_json_lost['data']['object'] + event_json_lost["data"]["object"] end - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } let(:event_json_created) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created-with-one-withdrawn') + json = StripeMockHelper.mock_webhook_event("charge.dispute.created-with-one-withdrawn") json end end @@ -1057,35 +1065,35 @@ include_context :dispute_lost_created_and_funds_withdrawn_at_same_time_context include_context :disputes_specs - it 'has status of lost' do - expect(obj.status).to eq 'lost' + it "has status of lost" do + expect(obj.status).to eq "lost" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -81500' do - expect(obj.net_change).to eq -81500 + it "has a net_change of -81500" do + expect(obj.net_change).to eq(-81500) end - it 'has an amount of 80000' do + it "has an amount of 80000" do expect(obj.amount).to eq 80000 end - it 'has a correct charge id' do + it "has a correct charge id" do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time end @@ -1094,67 +1102,69 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 80000 } specify { expect(subject.status).to eq "lost" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created_time} + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created_time } end - it 'has 1 dispute transactions' do + it "has 1 dispute transactions" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -80000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -81500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time} + specify { expect(subject.gross_amount).to eq(-80000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-81500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time } end - it 'has no reinstated transaction' do + it "has no reinstated transaction" do expect(reinstated_transaction).to be_nil end specify { expect(original_payment.refund_total).to eq 80000 } - let(:valid_events) { [:created, :funds_withdrawn, :lost]} + let(:valid_events) { [:created, :funds_withdrawn, :lost] } end RSpec.shared_context :__dispute_with_two_partial_disputes_withdrawn_at_same_time_context do include_context :disputes_context let(:event_json_dispute_partial1) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created-with-one-withdrawn--partial1') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.created-with-one-withdrawn--partial1") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let(:json_partial1) { event_json_dispute_partial1['data']['object']} + let(:json_partial1) { event_json_dispute_partial1["data"]["object"] } let(:event_json_dispute_partial2) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.created-with-one-withdrawn--partial2') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.created-with-one-withdrawn--partial2") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end - let(:json_partial2) {event_json_dispute_partial2['data']['object']} + let(:json_partial2) { event_json_dispute_partial2["data"]["object"] } - let!(:charge) { force_create(:charge, supporter: supporter, - stripe_charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC', nonprofit: nonprofit, payment:force_create(:payment, - supporter:supporter, - nonprofit: nonprofit, - gross_amount: 80000))} + let!(:charge) { + force_create(:charge, supporter: supporter, + stripe_charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC", nonprofit: nonprofit, payment: force_create(:payment, + supporter: supporter, + nonprofit: nonprofit, + gross_amount: 80000)) + } specify { expect(original_payment.refund_total).to eq 70000 } end @@ -1163,35 +1173,35 @@ include_context :__dispute_with_two_partial_disputes_withdrawn_at_same_time_context include_context :disputes_specs - it 'has status of needs_response' do - expect(obj.status).to eq 'needs_response' + it "has status of needs_response" do + expect(obj.status).to eq "needs_response" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -41500' do - expect(obj.net_change).to eq -41500 + it "has a net_change of -41500" do + expect(obj.net_change).to eq(-41500) end - it 'has an amount of 40000' do + it "has an amount of 40000" do expect(obj.amount).to eq 40000 end - it 'has a correct charge id' do + it "has a correct charge id" do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_05RsQX2eZvKYlo2C0FRTGSSA" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created_time__partial1 end @@ -1200,75 +1210,75 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 40000 } specify { expect(subject.status).to eq "needs_response" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created_time__partial1} + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created_time__partial1 } end - it 'has 1 dispute transactions' do + it "has 1 dispute transactions" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -40000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial1} + specify { expect(subject.gross_amount).to eq(-40000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial1 } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -40000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -41500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial1} + specify { expect(subject.gross_amount).to eq(-40000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-41500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial1 } end - it 'has no reinstated transaction' do + it "has no reinstated transaction" do expect(reinstated_transaction).to be_nil end - let(:valid_events) { [:created, :funds_withdrawn]} + let(:valid_events) { [:created, :funds_withdrawn] } end RSpec.shared_context :dispute_with_two_partial_disputes_withdrawn_at_same_time_spec__partial2 do include_context :__dispute_with_two_partial_disputes_withdrawn_at_same_time_context include_context :disputes_specs - it 'has status of needs_response' do - expect(obj.status).to eq 'needs_response' + it "has status of needs_response" do + expect(obj.status).to eq "needs_response" end - it 'has reason of duplicate' do - expect(obj.reason).to eq 'duplicate' + it "has reason of duplicate" do + expect(obj.reason).to eq "duplicate" end - it 'has 1 balance transactions' do + it "has 1 balance transactions" do expect(obj.balance_transactions.count).to eq 1 end - it 'has a net_change of -31500' do - expect(obj.net_change).to eq -31500 + it "has a net_change of -31500" do + expect(obj.net_change).to eq(-31500) end - it 'has an amount of 30000' do + it "has an amount of 30000" do expect(obj.amount).to eq 30000 end - it 'has a correct charge id' do + it "has a correct charge id" do expect(obj.stripe_charge_id).to eq "ch_1Y7zzfBCJIIhvMWmSiNWrPAC" end - it 'has a correct dispute id' do + it "has a correct dispute id" do expect(obj.stripe_dispute_id).to eq "dp_25RsQX2eZvKYlo2C0ZXCVBNM" end - it 'has a started_at of dispute_created_time' do + it "has a started_at of dispute_created_time" do expect(obj.started_at).to eq dispute_created__partial2 end @@ -1277,84 +1287,85 @@ specify { expect(subject).to be_persisted } specify { expect(subject.gross_amount).to eq 30000 } specify { expect(subject.status).to eq "needs_response" } - specify { expect(subject.reason).to eq 'duplicate' } - specify { expect(subject.started_at).to eq dispute_created__partial2} + specify { expect(subject.reason).to eq "duplicate" } + specify { expect(subject.started_at).to eq dispute_created__partial2 } end - it 'has 1 dispute transactions' do + it "has 1 dispute transactions" do expect(dispute_transactions.count).to eq 1 end - describe 'has a withdrawal_transaction' do - subject{ withdrawal_transaction } + describe "has a withdrawal_transaction" do + subject { withdrawal_transaction } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -30000 } - specify { expect(subject.fee_total).to eq -1500 } - specify { expect(subject.stripe_transaction_id).to eq 'txn_1Y7pdnBCJIIhvMWmJ9KQVpfB' } - specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial2} + specify { expect(subject.gross_amount).to eq(-30000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.stripe_transaction_id).to eq "txn_1Y7pdnBCJIIhvMWmJ9KQVpfB" } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial2 } specify { expect(subject.disbursed).to eq false } end - describe 'has a withdrawal_payment' do - subject { withdrawal_payment} + describe "has a withdrawal_payment" do + subject { withdrawal_payment } specify { expect(subject).to be_persisted } - specify { expect(subject.gross_amount).to eq -30000} - specify { expect(subject.fee_total).to eq -1500} - specify { expect(subject.net_amount).to eq -31500} - specify { expect(subject.kind).to eq 'Dispute'} - specify { expect(subject.nonprofit).to eq supporter.nonprofit} - specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial2} + specify { expect(subject.gross_amount).to eq(-30000) } + specify { expect(subject.fee_total).to eq(-1500) } + specify { expect(subject.net_amount).to eq(-31500) } + specify { expect(subject.kind).to eq "Dispute" } + specify { expect(subject.nonprofit).to eq supporter.nonprofit } + specify { expect(subject.date).to eq dispute_withdrawal_payment_time__partial2 } end - it 'has no reinstated transaction' do + it "has no reinstated transaction" do expect(reinstated_transaction).to be_nil end - let(:valid_events) { [:created, :funds_withdrawn]} + let(:valid_events) { [:created, :funds_withdrawn] } end RSpec.shared_context :legacy_dispute_context do - include_context :disputes_context - + include_context :disputes_context + let(:json) do dispute - event_json['data']['object'] + event_json["data"]["object"] end - let!(:dispute) { dispute = force_create(:dispute, stripe_dispute_id: event_json['data']['object']['id'], - is_legacy: true, - charge_id: 'ch_1Y7zzfBCJIIhvMWmSiNWrPAC') + let!(:dispute) { + dispute = force_create(:dispute, stripe_dispute_id: event_json["data"]["object"]["id"], + is_legacy: true, + charge_id: "ch_1Y7zzfBCJIIhvMWmSiNWrPAC") dispute.dispute_transactions.create(gross_amount: -80000, disbursed: true, payment: force_create(:payment, gross_amount: -80000, fee_total: -1500, net_amount: -81500)) dispute } - + let(:dispute_transactions) { dispute.dispute_transactions } # we reload this because we'll get the older version if we don't - let(:original_payment) { + let(:original_payment) { obj.dispute.original_payment.reload obj.dispute.original_payment } - let(:withdrawal_transaction) {dispute.dispute_transactions.order("date").first} - let(:withdrawal_payment) {withdrawal_transaction.payment} - let(:reinstated_transaction) {dispute.dispute_transactions.order("date").second} - let(:reinstated_payment) {reinstated_transaction.payment} + let(:withdrawal_transaction) { dispute.dispute_transactions.order("date").first } + let(:withdrawal_payment) { withdrawal_transaction.payment } + let(:reinstated_transaction) { dispute.dispute_transactions.order("date").second } + let(:reinstated_payment) { reinstated_transaction.payment } let(:event_json) do - json = StripeMockHelper.mock_webhook_event('charge.dispute.funds_withdrawn') - StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json['data']['object']) + json = StripeMockHelper.mock_webhook_event("charge.dispute.funds_withdrawn") + StripeMockHelper.stripe_helper.upsert_stripe_object(:dispute, json["data"]["object"]) json end end RSpec.shared_context :legacy_dispute_specs do include_context :legacy_dispute_context - include_context :disputes_specs - it 'has no Dispute.activities' do + include_context :disputes_specs + it "has no Dispute.activities" do dispute.reload expect(dispute.activities).to be_empty end - let(:valid_events) { []} -end \ No newline at end of file + let(:valid_events) { [] } +end diff --git a/spec/support/contexts/fee_structure_contexts.rb b/spec/support/contexts/fee_structure_contexts.rb index 7f9b518a2..5187227d9 100644 --- a/spec/support/contexts/fee_structure_contexts.rb +++ b/spec/support/contexts/fee_structure_contexts.rb @@ -1,22 +1,18 @@ - - - -RSpec.shared_examples 'a model which can validate international fees' do |local_fee_model, countryless_fee_model| - describe '#charge_international_fee?' do - - context 'when source is in same country' do - subject { create(:us_local_fee_structure)} - it { is_expected.to_not be_charge_international_fee(source_from_us)} +RSpec.shared_examples "a model which can validate international fees" do |local_fee_model, countryless_fee_model| + describe "#charge_international_fee?" do + context "when source is in same country" do + subject { create(:us_local_fee_structure) } + it { is_expected.to_not be_charge_international_fee(source_from_us) } end - context 'when source is in different country' do - subject { create(:us_local_fee_structure)} - it { is_expected.to be_charge_international_fee(source_from_uk)} + context "when source is in different country" do + subject { create(:us_local_fee_structure) } + it { is_expected.to be_charge_international_fee(source_from_uk) } end - context 'when fee structure has no local country' do - subject { create(:countryless_fee_structure)} - it { is_expected.to_not be_charge_international_fee(source_from_uk)} + context "when fee structure has no local country" do + subject { create(:countryless_fee_structure) } + it { is_expected.to_not be_charge_international_fee(source_from_uk) } end end -end \ No newline at end of file +end diff --git a/spec/support/contexts/general_shared_user_context.rb b/spec/support/contexts/general_shared_user_context.rb index fce269401..e5ca0185e 100644 --- a/spec/support/contexts/general_shared_user_context.rb +++ b/spec/support/contexts/general_shared_user_context.rb @@ -8,11 +8,11 @@ __create_admin(other_nonprofit) } - let(:user_as_np_associate){ + let(:user_as_np_associate) { __create_associate(nonprofit) } - let(:user_as_other_np_associate){ + let(:user_as_other_np_associate) { __create_associate(other_nonprofit) } @@ -20,17 +20,16 @@ force_create(:user) } - let(:campaign_editor) { __create(:campaign_editor, campaign) } - let(:confirmed_user){ + let(:confirmed_user) { force_create(:user, confirmed_at: Time.current) } let(:event_editor) { - __create(:event_editor,event) + __create(:event_editor, event) } let(:super_admin) { @@ -44,64 +43,59 @@ } let(:all_users) do - {:user_as_np_admin => user_as_np_admin, - :user_as_other_np_admin => user_as_other_np_admin, - :user_as_np_associate => user_as_np_associate, - :user_as_other_np_associate => user_as_other_np_associate, - :unauth_user => unauth_user, - :campaign_editor => campaign_editor, - :event_editor => event_editor, - :super_admin => super_admin, - :user_with_profile => user_with_profile - } + {user_as_np_admin: user_as_np_admin, + user_as_other_np_admin: user_as_other_np_admin, + user_as_np_associate: user_as_np_associate, + user_as_other_np_associate: user_as_other_np_associate, + unauth_user: unauth_user, + campaign_editor: campaign_editor, + event_editor: event_editor, + super_admin: super_admin, + user_with_profile: user_with_profile} end let(:roles__open_to_all) do [nil, :user_as_np_admin, - :user_as_other_np_admin, - :user_as_np_associate, - :user_as_other_np_associate, - :unauth_user, - :campaign_editor, - :event_editor, - :super_admin, - :user_with_profile - ] + :user_as_other_np_admin, + :user_as_np_associate, + :user_as_other_np_associate, + :unauth_user, + :campaign_editor, + :event_editor, + :super_admin, + :user_with_profile] end let(:roles__open_to_np_associate) do [:user_as_np_admin, - :user_as_np_associate, - - :super_admin + :user_as_np_associate, - ] + :super_admin] end let(:roles__open_to_campaign_editor) do [:user_as_np_admin, - :user_as_np_associate, - :campaign_editor, - :super_admin - ] + :user_as_np_associate, + :campaign_editor, + :super_admin] end def __create(name, host) u = force_create(:user) - force_create(:role, user: u, name: name, host:host) + force_create(:role, user: u, name: name, host: host) u end def __create_admin(host) u = force_create(:user) - force_create(:role, user: u, name: :nonprofit_admin, host:host) + force_create(:role, user: u, name: :nonprofit_admin, host: host) u end def __create_associate(host) u = force_create(:user) - force_create(:role, user: u, name: :nonprofit_associate, host:host) + force_create(:role, user: u, name: :nonprofit_associate, host: host) u end @@ -109,26 +103,26 @@ def run_authorization_tests(details, &block) @method = details[:method] @successful_users = details[:successful_users] @action = details[:action] - @block_to_get_arguments_to_run = block || ->(_) {} #no-op + @block_to_get_arguments_to_run = block || ->(_) {} # no-op accept_test_for_nil = false - all_users.each do |k,v| + all_users.each do |k, v| os = OpenStruct.new os.key = k os.value = v if k.nil? - accept(user_to_signin: nil, method:@method, action: @action, args: @block_to_get_arguments_to_run.call(v)) + accept(user_to_signin: nil, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v)) accept_test_for_nil = true end if @successful_users.include? k - accept(user_to_signin: os, method:@method, action: @action, args: @block_to_get_arguments_to_run.call(v)) + accept(user_to_signin: os, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v)) else - reject(user_to_signin: os, method:@method, action: @action, args: @block_to_get_arguments_to_run.call(v)) + reject(user_to_signin: os, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v)) end end unless accept_test_for_nil - reject(user_to_signin: nil, method:@method, action: @action, args: @block_to_get_arguments_to_run.call(nil)) + reject(user_to_signin: nil, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(nil)) end end -end \ No newline at end of file +end diff --git a/spec/support/contexts/houidable_context.rb b/spec/support/contexts/houidable_context.rb index 6917b681a..e816091f8 100644 --- a/spec/support/contexts/houidable_context.rb +++ b/spec/support/contexts/houidable_context.rb @@ -9,11 +9,10 @@ # the prefix is `:supp`. # @param [String, symbol] attribute the attribute where houids stored. This is usually `:houid` # but in some cases could be something else -shared_examples 'an houidable entity' do |prefix, attribute| - +shared_examples "an houidable entity" do |prefix, attribute| let!(:instance) { subject } let(:houid_attribute) { attribute || :houid } - + it { is_expected.to have_attributes(houid_prefix: prefix.to_sym) } @@ -22,13 +21,13 @@ is_expected.to have_attributes(houid_attribute: houid_attribute.to_sym) } - describe 'class methods' do + describe "class methods" do it { expect(instance.class).to have_attributes(houid_prefix: prefix.to_sym) } - + it { expect(instance.class).to have_attributes(houid_attribute: houid_attribute.to_sym) - } + } end -end \ No newline at end of file +end diff --git a/spec/support/contexts/payments_extension_context.rb b/spec/support/contexts/payments_extension_context.rb index a795e1010..bb020ad5e 100644 --- a/spec/support/contexts/payments_extension_context.rb +++ b/spec/support/contexts/payments_extension_context.rb @@ -3,21 +3,20 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -shared_examples 'a class with payments extension' do |association_attribute, factory| +shared_examples "a class with payments extension" do |association_attribute, factory| let!(:instance) { create(factory) } - context 'association' do + context "association" do let(:association) { instance.send(association_attribute) } - it { expect(association).to have_attributes(gross_amount: 707, net_amount: 700, fee_total: -7) } it { - expect(association).to have_attributes(currency: 'fake') + expect(association).to have_attributes(currency: "fake") } end -end \ No newline at end of file +end diff --git a/spec/support/contexts/shared_donation_charge_context.rb b/spec/support/contexts/shared_donation_charge_context.rb index 10c4b4141..7a30271ad 100644 --- a/spec/support/contexts/shared_donation_charge_context.rb +++ b/spec/support/contexts/shared_donation_charge_context.rb @@ -1,59 +1,58 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'stripe_mock' +require "stripe_mock" RSpec.shared_context :shared_donation_charge_context do - let(:nonprofit) { - stripe_account = create(:stripe_account, charges_enabled:true) - force_create(:nonprofit, name: "nonprofit name", slug: 'nonprofit_nameo', stripe_account_id: stripe_account.stripe_account_id) + let(:nonprofit) { + stripe_account = create(:stripe_account, charges_enabled: true) + force_create(:nonprofit, name: "nonprofit name", slug: "nonprofit_nameo", stripe_account_id: stripe_account.stripe_account_id) } - let(:other_nonprofit) { force_create(:nonprofit)} - let(:supporter) {force_create(:supporter, :nonprofit => nonprofit, locale: 'locale_one')} - let(:other_nonprofit_supporter) { force_create(:supporter, nonprofit: other_nonprofit, locale: 'locale_two')} - let(:card) {force_create(:card, :holder => supporter)} - let(:card_for_other_supporter) { force_create(:card, holder: other_nonprofit_supporter)} - let(:card_with_valid_stripe_id) { force_create(:card, :holder => supporter)} - let(:direct_debit_detail) { force_create(:direct_debit_detail, holder:supporter)} - let(:direct_debit_detail_for_other_supporter) { force_create(:direct_debit_detail, holder: other_nonprofit_supporter)} + let(:other_nonprofit) { force_create(:nonprofit) } + let(:supporter) { force_create(:supporter, nonprofit: nonprofit, locale: "locale_one") } + let(:other_nonprofit_supporter) { force_create(:supporter, nonprofit: other_nonprofit, locale: "locale_two") } + let(:card) { force_create(:card, holder: supporter) } + let(:card_for_other_supporter) { force_create(:card, holder: other_nonprofit_supporter) } + let(:card_with_valid_stripe_id) { force_create(:card, holder: supporter) } + let(:direct_debit_detail) { force_create(:direct_debit_detail, holder: supporter) } + let(:direct_debit_detail_for_other_supporter) { force_create(:direct_debit_detail, holder: other_nonprofit_supporter) } let(:bp_percentage) { 0.039 } - let(:billing_plan) {force_create(:billing_plan, :percentage_fee => bp_percentage)} - let(:billing_subscription) { force_create(:billing_subscription, :billing_plan => billing_plan, :nonprofit => nonprofit)} - let(:campaign) {force_create(:campaign, nonprofit: nonprofit, goal_amount: 500)} - let(:other_campaign) {force_create(:campaign, nonprofit: other_nonprofit)} + let(:billing_plan) { force_create(:billing_plan, percentage_fee: bp_percentage) } + let(:billing_subscription) { force_create(:billing_subscription, billing_plan: billing_plan, nonprofit: nonprofit) } + let(:campaign) { force_create(:campaign, nonprofit: nonprofit, goal_amount: 500) } + let(:other_campaign) { force_create(:campaign, nonprofit: other_nonprofit) } let(:event) { - Event.any_instance.stub(:geocode).and_return([1,1]) + Event.any_instance.stub(:geocode).and_return([1, 1]) force_create(:event, nonprofit: nonprofit) } let(:other_event) { - Event.any_instance.stub(:geocode).and_return([1,1]) + Event.any_instance.stub(:geocode).and_return([1, 1]) force_create(:event, nonprofit: other_nonprofit) } - let(:event_discount) {force_create(:event_discount, event: event, percent: 20)} - let(:other_event_discount) {force_create(:event_discount, event: other_event)} - let(:profile) {force_create(:profile)} - let(:user) { force_create(:user)} - let(:ticket_level) {force_create(:ticket_level, event: event, amount: 400, name: "1")} - let(:ticket_level2) {force_create(:ticket_level, event: event, amount: 500, name: "2")} - let(:free_ticket_level) {force_create(:ticket_level, event: event, amount: 0, name: 'free ticket level')} - let(:other_ticket_level) {force_create(:ticket_level, event: other_event, name: "3")} + let(:event_discount) { force_create(:event_discount, event: event, percent: 20) } + let(:other_event_discount) { force_create(:event_discount, event: other_event) } + let(:profile) { force_create(:profile) } + let(:user) { force_create(:user) } + let(:ticket_level) { force_create(:ticket_level, event: event, amount: 400, name: "1") } + let(:ticket_level2) { force_create(:ticket_level, event: event, amount: 500, name: "2") } + let(:free_ticket_level) { force_create(:ticket_level, event: event, amount: 0, name: "free ticket level") } + let(:other_ticket_level) { force_create(:ticket_level, event: other_event, name: "3") } - let(:donation_for_rd) {force_create(:donation, recurring: true, nonprofit: nonprofit, supporter: supporter, card: card_with_valid_stripe_id, amount: 500)} - let(:recurring_donation) {force_create(:recurring_donation, donation: donation_for_rd, nonprofit: nonprofit, supporter:supporter, start_date: Time.now, interval: 1, time_unit: 'month')} - - let!(:current_fee_era) { create(:fee_era_with_structures)} - let!(:previous_fee_era) { create(:fee_era_with_no_start)} - let!(:future_fee_era) { create(:fee_era_with_no_end)} + let(:donation_for_rd) { force_create(:donation, recurring: true, nonprofit: nonprofit, supporter: supporter, card: card_with_valid_stripe_id, amount: 500) } + let(:recurring_donation) { force_create(:recurring_donation, donation: donation_for_rd, nonprofit: nonprofit, supporter: supporter, start_date: Time.now, interval: 1, time_unit: "month") } + let!(:current_fee_era) { create(:fee_era_with_structures) } + let!(:previous_fee_era) { create(:fee_era_with_no_start) } + let!(:future_fee_era) { create(:fee_era_with_no_end) } - def generate_card_token(brand="Visa", country='US') + def generate_card_token(brand = "Visa", country = "US") StripeMockHelper.generate_card_token({brand: brand, country: country}) end - around(:each){|example| + around(:each) { |example| Timecop.freeze(2020, 5, 4) do - StripeMockHelper.mock do + StripeMockHelper.mock do example.run end end } -end \ No newline at end of file +end diff --git a/spec/support/contexts/shared_rd_donation_value_context.rb b/spec/support/contexts/shared_rd_donation_value_context.rb index 103a2ffb7..a519d7f8b 100644 --- a/spec/support/contexts/shared_rd_donation_value_context.rb +++ b/spec/support/contexts/shared_rd_donation_value_context.rb @@ -3,151 +3,143 @@ RSpec.shared_context :shared_rd_donation_value_context do include_context :shared_donation_charge_context - let(:fake_uuid) {"53a6bc06-0789-11e8-bb3f-f34cac607737"} - let(:valid_uuid) {'fcf61bac-078a-11e8-aa53-cba5bdb8dcdd'} - let(:other_uuid) {'a713018c-078f-11e8-ae3b-bf5007844fea'} - let(:source_token) {force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: valid_uuid) } + let(:fake_uuid) { "53a6bc06-0789-11e8-bb3f-f34cac607737" } + let(:valid_uuid) { "fcf61bac-078a-11e8-aa53-cba5bdb8dcdd" } + let(:other_uuid) { "a713018c-078f-11e8-ae3b-bf5007844fea" } + let(:source_token) { force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: valid_uuid) } let(:source_tokens) { (0..10).map { |i| - force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: SecureRandom.uuid) + force_create(:source_token, tokenizable: card, expiration: Time.now + 1.day, max_uses: 1, token: SecureRandom.uuid) } } - let(:other_source_token) {force_create(:source_token, tokenizable: card_for_other_supporter, expiration: Time.now + 1.day, max_uses: 1, token: other_uuid)} + let(:other_source_token) { force_create(:source_token, tokenizable: card_for_other_supporter, expiration: Time.now + 1.day, max_uses: 1, token: other_uuid) } - let(:charge_amount) {100} + let(:charge_amount) { 100 } - let(:default_edit_token) {'7903e34c-10fe-11e8-9ead-d302c690bee4'} - before(:each){ - Event.any_instance.stub(:geocode).and_return([1,1]) + let(:default_edit_token) { "7903e34c-10fe-11e8-9ead-d302c690bee4" } + before(:each) { + Event.any_instance.stub(:geocode).and_return([1, 1]) } - def generate_expected(donation_id, payment_id, charge_id, card, supporter, nonprofit, stripe_charge_id, data = {}) - - payment_stuff = {} payment_stuff[:card_id] = card.id if card.is_a? Card payment_stuff[:direct_debit_detail_id] = card.id if card.is_a? DirectDebitDetail - payment_stuff[:provider] = card.is_a?(Card) ? 'credit_card' : 'sepa' + payment_stuff[:provider] = card.is_a?(Card) ? "credit_card" : "sepa" payment_stuff[:fee] = card.is_a?(Card) ? 36 : 0 result = { - donation: { - id: donation_id, - nonprofit_id: nonprofit.id, - supporter_id: supporter.id, - - card_id: payment_stuff[:card_id], - - date: Time.now, - created_at: Time.now, - updated_at: Time.now, - event_id: data[:event] ? event.id : nil, - campaign_id: data[:campaign] ? campaign.id : nil, - anonymous: false, - amount: charge_amount, - comment: nil, - category: nil, - dedication: 'dedication', - designation: 'designation', - imported_at: nil, - manual: nil, - offsite: nil, - recurring: nil, - recurring_donation_id: nil, - origin_url: nil, - payment_id: nil, - profile_id: nil, - - charge_id: nil, - payment_provider: payment_stuff[:provider], - queued_for_import_at: nil, - direct_debit_detail_id: payment_stuff[:direct_debit_detail_id], - fts: an_instance_of(String).or(be_nil) - }, - + donation: { + id: donation_id, + nonprofit_id: nonprofit.id, + supporter_id: supporter.id, + + card_id: payment_stuff[:card_id], + + date: Time.now, + created_at: Time.now, + updated_at: Time.now, + event_id: data[:event] ? event.id : nil, + campaign_id: data[:campaign] ? campaign.id : nil, + anonymous: false, + amount: charge_amount, + comment: nil, + category: nil, + dedication: "dedication", + designation: "designation", + imported_at: nil, + manual: nil, + offsite: nil, + recurring: nil, + recurring_donation_id: nil, + origin_url: nil, + payment_id: nil, + profile_id: nil, + + charge_id: nil, + payment_provider: payment_stuff[:provider], + queued_for_import_at: nil, + direct_debit_detail_id: payment_stuff[:direct_debit_detail_id], + fts: an_instance_of(String).or(be_nil) + } }.with_indifferent_access - unless (payment_id == nil) + unless payment_id.nil? result[:activity] = {} - result[:payment] = { - date: Time.now, - donation_id: donation_id, - fee_total: -payment_stuff[:fee], - gross_amount: 100, - id: payment_id || 55555, - kind: data[:recurring_donation] ? 'RecurringDonation' : 'Donation', - net_amount: 100 - payment_stuff[:fee], - nonprofit_id: nonprofit.id, - refund_total: 0, - supporter_id: supporter.id, - towards: 'designation', - created_at: Time.now, - updated_at: Time.now + date: Time.now, + donation_id: donation_id, + fee_total: -payment_stuff[:fee], + gross_amount: 100, + id: payment_id || 55555, + kind: data[:recurring_donation] ? "RecurringDonation" : "Donation", + net_amount: 100 - payment_stuff[:fee], + nonprofit_id: nonprofit.id, + refund_total: 0, + supporter_id: supporter.id, + towards: "designation", + created_at: Time.now, + updated_at: Time.now } result[:charge] = { - id: charge_id || 55555, - amount: charge_amount, - - card_id: payment_stuff[:card_id], - created_at: Time.now, - updated_at: Time.now, - stripe_charge_id: stripe_charge_id, - fee: payment_stuff[:fee], - - disbursed: nil, - failure_message: nil, - payment_id: payment_id || 55555, - nonprofit_id: nonprofit.id, - status: 'pending', - profile_id: nil, - supporter_id: supporter.id, - ticket_id: nil, - - donation_id: donation_id, - direct_debit_detail_id: payment_stuff[:direct_debit_detail_id] + id: charge_id || 55555, + amount: charge_amount, + + card_id: payment_stuff[:card_id], + created_at: Time.now, + updated_at: Time.now, + stripe_charge_id: stripe_charge_id, + fee: payment_stuff[:fee], + + disbursed: nil, + failure_message: nil, + payment_id: payment_id || 55555, + nonprofit_id: nonprofit.id, + status: "pending", + profile_id: nil, + supporter_id: supporter.id, + ticket_id: nil, + + donation_id: donation_id, + direct_debit_detail_id: payment_stuff[:direct_debit_detail_id] } end - if (data[:recurring_donation]) + if data[:recurring_donation] result[:recurring_donation] = { - id: data[:recurring_donation].id, - active: true, - paydate: data[:recurring_donation_expected][:paydate], - interval: data[:recurring_donation_expected][:interval], - time_unit: data[:recurring_donation_expected][:time_unit], - start_date: data[:recurring_donation_expected][:start_date], - end_date: nil, - n_failures: 0, - edit_token: default_edit_token, - cancelled_by: nil, - cancelled_at: nil, - donation_id: donation_id, - nonprofit_id: nonprofit.id, - created_at: Time.now, - updated_at: Time.now, - failure_message: nil, - origin_url: nil, - amount: charge_amount, - supporter_id: supporter.id, - - - #removable fields - card_id: nil, - campaign_id: nil, - anonymous: false, - email: supporter.email, - profile_id: nil - + id: data[:recurring_donation].id, + active: true, + paydate: data[:recurring_donation_expected][:paydate], + interval: data[:recurring_donation_expected][:interval], + time_unit: data[:recurring_donation_expected][:time_unit], + start_date: data[:recurring_donation_expected][:start_date], + end_date: nil, + n_failures: 0, + edit_token: default_edit_token, + cancelled_by: nil, + cancelled_at: nil, + donation_id: donation_id, + nonprofit_id: nonprofit.id, + created_at: Time.now, + updated_at: Time.now, + failure_message: nil, + origin_url: nil, + amount: charge_amount, + supporter_id: supporter.id, + + # removable fields + card_id: nil, + campaign_id: nil, + anonymous: false, + email: supporter.email, + profile_id: nil } - end result @@ -155,57 +147,48 @@ def generate_expected(donation_id, payment_id, charge_id, card, supporter, nonpr def validation_unauthorized expect(QuerySourceToken).to receive(:get_and_increment_source_token).with(fake_uuid, nil).and_raise(AuthenticationError) - expect {yield()}.to raise_error {|e| + expect { yield() }.to raise_error { |e| expect(e).to be_a(AuthenticationError) }.and not_change { ObjectEvent.count } end def validation_expired expect(QuerySourceToken).to receive(:get_and_increment_source_token).with(fake_uuid, nil).and_raise(ExpiredTokenError) - expect {yield()}.to raise_error {|e| - + expect { yield() }.to raise_error { |e| expect(e).to be_a(ExpiredTokenError) }.and not_change { ObjectEvent.count } end def validation_basic_validation - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a(ParamValidation::ValidationError) - expect(e.message).to start_with 'amount' + expect(e.message).to start_with "amount" expect_validation_errors(e.data, [ - {key: :amount, name: :required}, - {key: :amount, name: :is_integer}, - {key: :nonprofit_id, name: :required}, - {key: :nonprofit_id, name: :is_reference}, - {key: :supporter_id, name: :required}, - {key: :supporter_id, name: :is_reference}, - {key: :designation, name: :is_a}, - {key: :dedication, name: :is_a}, - {key: :campaign_id, name: :is_reference}, - {key: :event_id, name: :is_reference}, - {key: :token, name: :required}, - {key: :token, name: :format}, + {key: :amount, name: :required}, + {key: :amount, name: :is_integer}, + {key: :nonprofit_id, name: :required}, + {key: :nonprofit_id, name: :is_reference}, + {key: :supporter_id, name: :required}, + {key: :supporter_id, name: :is_reference}, + {key: :designation, name: :is_a}, + {key: :dedication, name: :is_a}, + {key: :campaign_id, name: :is_reference}, + {key: :event_id, name: :is_reference}, + {key: :token, name: :required}, + {key: :token, name: :format} ]) }.and not_change { ObjectEvent.count } end def validation_invalid_token - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a(ParamValidation::ValidationError) expect(e.message).to eq "#{fake_uuid} doesn't represent a valid source" }.and not_change { ObjectEvent.count } - end - def find_error_supporter - return expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :supporter_id}]) @@ -213,18 +196,14 @@ def find_error_supporter end def find_error_nonprofit - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :nonprofit_id}]) }.and not_change { ObjectEvent.count } end def find_error_campaign - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :campaign_id}]) @@ -232,43 +211,33 @@ def find_error_campaign end def find_error_event - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :event_id}]) }.and not_change { ObjectEvent.count } end def find_error_ticket - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :ticket_id}]) } end def find_error_profile - expect {yield()}.to raise_error {|e| - - + expect { yield() }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError expect_validation_errors(e.data, [{key: :profile_id}]) } end - - def validation_supporter_deleted supporter supporter.deleted = true supporter.save! - expect {yield}.to raise_error {|e| - - + expect { yield }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError - expect(e.message).to include 'deleted' + expect(e.message).to include "deleted" expect_validation_errors(e.data, [{key: :supporter_id}]) }.and not_change { ObjectEvent.count } end @@ -277,11 +246,10 @@ def validation_event_deleted event.deleted = true event.save! - expect { yield }.to raise_error {|error| - + expect { yield }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :event_id}]) - expect(error.message).to include 'deleted' + expect(error.message).to include "deleted" expect(error.message).to include "Event #{event.id}" }.and not_change { ObjectEvent.count } end @@ -290,67 +258,56 @@ def validation_campaign_deleted campaign.deleted = true campaign.save! - expect { yield }.to raise_error {|error| - + expect { yield }.to raise_error { |error| expect(error).to be_a ParamValidation::ValidationError expect_validation_errors(error.data, [{key: :campaign_id}]) - expect(error.message).to include 'deleted' + expect(error.message).to include "deleted" expect(error.message).to include "Campaign #{campaign.id}" } end def validation_supporter_not_with_nonprofit - expect {yield}.to raise_error {|e| - - + expect { yield }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError - expect(e.message).to include 'Supporter' - expect(e.message).to include 'does not belong to nonprofit' + expect(e.message).to include "Supporter" + expect(e.message).to include "does not belong to nonprofit" expect_validation_errors(e.data, [{key: :supporter_id}]) } end def validation_campaign_not_with_nonprofit - expect {yield}.to raise_error {|e| - - + expect { yield }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError - expect(e.message).to include 'Campaign' - expect(e.message).to include 'does not belong to nonprofit' + expect(e.message).to include "Campaign" + expect(e.message).to include "does not belong to nonprofit" expect_validation_errors(e.data, [{key: :campaign_id}]) } end def validation_event_not_with_nonprofit - expect {yield}.to raise_error {|e| - - + expect { yield }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError - expect(e.message).to include 'Event' - expect(e.message).to include 'does not belong to nonprofit' + expect(e.message).to include "Event" + expect(e.message).to include "does not belong to nonprofit" expect_validation_errors(e.data, [{key: :event_id}]) }.and not_change { ObjectEvent.count } end def validation_card_not_with_supporter - expect {yield}.to raise_error {|e| - - + expect { yield }.to raise_error { |e| expect(e).to be_a ParamValidation::ValidationError - expect(e.message).to include 'Supporter' - expect(e.message).to include 'does not own card' + expect(e.message).to include "Supporter" + expect(e.message).to include "does not own card" expect_validation_errors(e.data, [{key: :token}]) }.and not_change { ObjectEvent.count } end def handle_charge_failed - failure_message = 'failure message' - - expect(InsertCharge).to receive(:with_stripe).and_return({'charge' => {'status' => 'failed', 'failure_message' => failure_message}}) - - expect {yield}.to raise_error {|e| + failure_message = "failure message" + expect(InsertCharge).to receive(:with_stripe).and_return({"charge" => {"status" => "failed", "failure_message" => failure_message}}) + expect { yield }.to raise_error { |e| expect(e).to be_a ChargeError expect(e.message).to eq failure_message @@ -363,51 +320,50 @@ def handle_charge_failed def before_each_success(expect_payment = true) expect(InsertDonation).to receive(:insert_donation).and_wrap_original do |m, *args| - result = m.call(*args); + result = m.call(*args) @donation_id = result.id - expect_job_queued.with(JobTypes::DonationPaymentCreateJob, @donation_id, expect_payment ? kind_of(Numeric) : nil , supporter.locale) + expect_job_queued.with(JobTypes::DonationPaymentCreateJob, @donation_id, expect_payment ? kind_of(Numeric) : nil, supporter.locale) result end - if (expect_payment) - nonprofit.stripe_account_id = Stripe::Account.create()['id'] + if expect_payment + nonprofit.stripe_account_id = Stripe::Account.create["id"] nonprofit.save! - card.stripe_customer_id = 'some other id' - cust = Stripe::Customer.create() - card.stripe_customer_id = cust['id'] + card.stripe_customer_id = "some other id" + cust = Stripe::Customer.create + card.stripe_customer_id = cust["id"] source = Stripe::Customer.create_source(cust.id, {source: StripeMockHelper.generate_card_token}) card.stripe_card_id = source.id card.save! - expect(Stripe::Charge).to receive(:create).and_wrap_original {|m, *args| a = m.call(*args); - @stripe_charge_id = a['id'] - a + expect(Stripe::Charge).to receive(:create).and_wrap_original { |m, *args| + a = m.call(*args) + @stripe_charge_id = a["id"] + a } end end - def before_each_successful_refund() + def before_each_successful_refund expect(InsertRefund).to receive(:with_stripe).and_wrap_original do |m, *args| - result = m.call(*args); + result = m.call(*args) @all_refunds&.push(result) || @all_refunds = [result] - @fifo_refunds&.unshift(result) || @fifo_refunds = [ result] + @fifo_refunds&.unshift(result) || @fifo_refunds = [result] result end - expect(Stripe::Refund).to receive(:create).and_wrap_original do |m, *args| - a = m.call(*args); - @stripe_refund_ids&.unshift(a['id']) || @stripe_refund_ids = [a['id']]; + expect(Stripe::Refund).to receive(:create).and_wrap_original do |m, *args| + a = m.call(*args) + @stripe_refund_ids&.unshift(a["id"]) || @stripe_refund_ids = [a["id"]] a end - end - - def before_each_sepa_success() + def before_each_sepa_success expect(InsertDonation).to receive(:insert_donation).and_wrap_original do |m, *args| - result = m.call(*args); + result = m.call(*args) @donation_id = result.id expect_job_queued.with(JobTypes::NonprofitPaymentNotificationJob, @donation_id, @payment_id) expect_job_queued.with(JobTypes::DonorDirectDebitNotificationJob, @donation_id, @payment_id, supporter.locale) @@ -418,35 +374,34 @@ def before_each_sepa_success() def process_event_donation(data = {}) pay_method = data[:sepa] ? direct_debit_detail : card result = yield - expected = generate_expected(@donation_id, result['payment'].id, result['charge'].id, pay_method, supporter, nonprofit, @stripe_charge_id, event: event, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation']) + expected = generate_expected(@donation_id, result["payment"].id, result["charge"].id, pay_method, supporter, nonprofit, @stripe_charge_id, event: event, recurring_donation_expected: data[:recurring_donation], recurring_donation: result["recurring_donation"]) expect(result.count).to eq expected.count - expect(result['donation'].attributes).to match expected[:donation] - expect(result['charge'].attributes).to eq expected[:charge] - #expect(result[:json]['activity']).to eq expected[:activity] - expect(result['payment'].attributes).to eq expected[:payment] - if (data[:recurring_donation]) - expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation] + expect(result["donation"].attributes).to match expected[:donation] + expect(result["charge"].attributes).to eq expected[:charge] + # expect(result[:json]['activity']).to eq expected[:activity] + expect(result["payment"].attributes).to eq expected[:payment] + if data[:recurring_donation] + expect(result["recurring_donation"].attributes).to eq expected[:recurring_donation] end - return result + result end def process_campaign_donation(data = {}) - pay_method = data[:sepa] ? direct_debit_detail : card result = yield - expected = generate_expected(@donation_id, result['payment'].id, result['charge'].id, pay_method, supporter, nonprofit, @stripe_charge_id, campaign: campaign, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation']) + expected = generate_expected(@donation_id, result["payment"].id, result["charge"].id, pay_method, supporter, nonprofit, @stripe_charge_id, campaign: campaign, recurring_donation_expected: data[:recurring_donation], recurring_donation: result["recurring_donation"]) expect(result.count).to eq expected.count - expect(result['donation'].attributes).to match expected[:donation] - expect(result['charge'].attributes).to eq expected[:charge] - #expect(result[:json]['activity']).to eq expected[:activity] - expect(result['payment'].attributes).to eq expected[:payment] - if (data[:recurring_donation]) - expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation] + expect(result["donation"].attributes).to match expected[:donation] + expect(result["charge"].attributes).to eq expected[:charge] + # expect(result[:json]['activity']).to eq expected[:activity] + expect(result["payment"].attributes).to eq expected[:payment] + if data[:recurring_donation] + expect(result["recurring_donation"].attributes).to eq expected[:recurring_donation] end - return result + result end def process_general_donation(data = {}) @@ -455,27 +410,27 @@ def process_general_donation(data = {}) expect_payment = nil_or_true(data[:expect_payment]) expect_charge = nil_or_true(data[:expect_charge]) - expected = generate_expected(@donation_id, nil_or_true(data[:expect_payment]) ? result['payment'].id : nil, nil_or_true(data[:expect_payment]) ? result['charge'].id : nil, pay_method, supporter, nonprofit, @stripe_charge_id, recurring_donation_expected: data[:recurring_donation], recurring_donation: result['recurring_donation']) + expected = generate_expected(@donation_id, nil_or_true(data[:expect_payment]) ? result["payment"].id : nil, nil_or_true(data[:expect_payment]) ? result["charge"].id : nil, pay_method, supporter, nonprofit, @stripe_charge_id, recurring_donation_expected: data[:recurring_donation], recurring_donation: result["recurring_donation"]) - expected['donation'].merge!(profile_id: profile.id) + expected["donation"].merge!(profile_id: profile.id) expect(result.count).to eq expected.count - expect(result['donation'].attributes).to match expected[:donation] - if (expect_charge) - expect(result['charge'].attributes).to eq expected[:charge] + expect(result["donation"].attributes).to match expected[:donation] + if expect_charge + expect(result["charge"].attributes).to eq expected[:charge] end - #expect(result[:json]['activity']).to eq expected[:activity] + # expect(result[:json]['activity']).to eq expected[:activity] - if (expect_payment) - expect(result['payment'].attributes).to eq expected[:payment] + if expect_payment + expect(result["payment"].attributes).to eq expected[:payment] end - if (data[:recurring_donation]) - expect(result['recurring_donation'].attributes).to eq expected[:recurring_donation] + if data[:recurring_donation] + expect(result["recurring_donation"].attributes).to eq expected[:recurring_donation] end - return result + result end def nil_or_true(item) item.nil? || item end -end \ No newline at end of file +end diff --git a/spec/support/contexts/stripe_contexts.rb b/spec/support/contexts/stripe_contexts.rb index 57f7c6099..b346299cf 100644 --- a/spec/support/contexts/stripe_contexts.rb +++ b/spec/support/contexts/stripe_contexts.rb @@ -1,10 +1,10 @@ -RSpec.shared_context "Stripe::Source doubles" do - let(:source_from_us) { double("A US based VISA card", country: 'US', brand: 'Visa')} - let(:visa_card) {source_from_us} - let(:uk_visa_card) {double("A UK based VISA card", country: 'UK', brand: 'Visa') } - let(:source_from_uk) { double("A UK based American Express card", country: 'UK', brand: 'American Express')} - let(:amex_card) { source_from_uk} - let(:source_from_ru) { double("A Russian based Discover card", country: 'RU', brand: 'Discover')} - let(:ru_discover_card) {source_from_ru} - let(:discover_card) {double("A US based Discover card", country: 'US', brand: 'Discover')} +RSpec.shared_context "Stripe::Source doubles" do + let(:source_from_us) { double("A US based VISA card", country: "US", brand: "Visa") } + let(:visa_card) { source_from_us } + let(:uk_visa_card) { double("A UK based VISA card", country: "UK", brand: "Visa") } + let(:source_from_uk) { double("A UK based American Express card", country: "UK", brand: "American Express") } + let(:amex_card) { source_from_uk } + let(:source_from_ru) { double("A Russian based Discover card", country: "RU", brand: "Discover") } + let(:ru_discover_card) { source_from_ru } + let(:discover_card) { double("A US based Discover card", country: "US", brand: "Discover") } end diff --git a/spec/support/contexts/subtransactable_context.rb b/spec/support/contexts/subtransactable_context.rb index 1ee1713a5..e5f01e5c6 100644 --- a/spec/support/contexts/subtransactable_context.rb +++ b/spec/support/contexts/subtransactable_context.rb @@ -3,14 +3,13 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -shared_examples 'subtransactable' do |prefix, factory_for_payment_extension_testing| - +shared_examples "subtransactable" do |prefix, factory_for_payment_extension_testing| it_behaves_like "an houidable entity", prefix, :houid - it_behaves_like 'a class with payments extension', :subtransaction_payments, factory_for_payment_extension_testing - - it_behaves_like 'an object with as_money attributes', :amount, :net_amount - + it_behaves_like "a class with payments extension", :subtransaction_payments, factory_for_payment_extension_testing + + it_behaves_like "an object with as_money attributes", :amount, :net_amount + it { is_expected.to have_one(:subtransaction).dependent(:nullify) } @@ -19,8 +18,7 @@ is_expected.to(have_one(:trx) .class_name("Transaction") .through(:subtransaction) - .with_foreign_key('transaction_id') - ) + .with_foreign_key("transaction_id")) } it { @@ -38,4 +36,4 @@ it { is_expected.to delegate_method(:currency).to(:nonprofit) } -end \ No newline at end of file +end diff --git a/spec/support/contexts/subtransaction_paymentable_context.rb b/spec/support/contexts/subtransaction_paymentable_context.rb index 95fe9c42f..31e1210f4 100644 --- a/spec/support/contexts/subtransaction_paymentable_context.rb +++ b/spec/support/contexts/subtransaction_paymentable_context.rb @@ -3,9 +3,9 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -shared_examples 'subtransaction paymentable' do |prefix| +shared_examples "subtransaction paymentable" do |prefix| it_behaves_like "an houidable entity", prefix, :houid - it_behaves_like 'an object with as_money attributes', :gross_amount, :net_amount, :fee_total + it_behaves_like "an object with as_money attributes", :gross_amount, :net_amount, :fee_total it { is_expected.to have_one(:subtransaction_payment).dependent(:destroy) @@ -15,15 +15,13 @@ is_expected.to(have_one(:trx) .class_name("Transaction") .through(:subtransaction_payment) - .with_foreign_key('transaction_id') - ) + .with_foreign_key("transaction_id")) } it { is_expected.to(have_one(:legacy_payment) - .class_name('Payment') - .through(:subtransaction_payment) - ) + .class_name("Payment") + .through(:subtransaction_payment)) } it { @@ -57,4 +55,4 @@ it { is_expected.to delegate_method(:currency).to(:nonprofit) } -end \ No newline at end of file +end diff --git a/spec/support/contexts/trx_assignable_context.rb b/spec/support/contexts/trx_assignable_context.rb index de27e777b..61b7027d8 100644 --- a/spec/support/contexts/trx_assignable_context.rb +++ b/spec/support/contexts/trx_assignable_context.rb @@ -3,10 +3,9 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -shared_examples 'trx assignable' do |prefix| +shared_examples "trx assignable" do |prefix| + it_behaves_like "an houidable entity", prefix, :houid - it_behaves_like 'an houidable entity', prefix, :houid - it { is_expected.to have_one(:transaction_assignment) } @@ -15,8 +14,7 @@ is_expected.to(have_one(:trx) .class_name("Transaction") .through(:transaction_assignment) - .with_foreign_key('transaction_id') - ) + .with_foreign_key("transaction_id")) } it { @@ -34,4 +32,4 @@ it { is_expected.to delegate_method(:currency).to(:nonprofit) } -end \ No newline at end of file +end diff --git a/spec/support/date_time.rb b/spec/support/date_time.rb index 33a3966cd..0b09d9055 100644 --- a/spec/support/date_time.rb +++ b/spec/support/date_time.rb @@ -3,4 +3,4 @@ class DateTime def nsec (sec_fraction * 1_000_000_000).to_i end -end \ No newline at end of file +end diff --git a/spec/support/expect.rb b/spec/support/expect.rb index b53413e1d..768b82552 100644 --- a/spec/support/expect.rb +++ b/spec/support/expect.rb @@ -1,23 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module Expect - - def expect_validation_errors(list_of_errors, validators, error_validator_length_should_match=true) - if (list_of_errors.is_a?(ParamValidation::ValidationError)) + def expect_validation_errors(list_of_errors, validators, error_validator_length_should_match = true) + if list_of_errors.is_a?(ParamValidation::ValidationError) list_of_errors = list_of_errors.data end - if (list_of_errors.is_a?(Hash)) + if list_of_errors.is_a?(Hash) list_of_errors = [list_of_errors] end - if (validators.is_a?(Hash)) + if validators.is_a?(Hash) validators = [validators] end - if (error_validator_length_should_match) + if error_validator_length_should_match expect(list_of_errors.length).to eq(validators.length) end - validators.each{|i| - expect(list_of_errors.any?{|e| e[:key].to_s == i[:key].to_s && e[:name].to_s == i[:name].to_s}).to eq(true), "#{i[:key]} should have existed for #{i[:name]}" + validators.each { |i| + expect(list_of_errors.any? { |e| e[:key].to_s == i[:key].to_s && e[:name].to_s == i[:name].to_s }).to eq(true), "#{i[:key]} should have existed for #{i[:name]}" } end @@ -29,7 +28,7 @@ def expect_job_not_queued expect(JobQueue).to_not receive(:queue) end - def match_houid(prefix) + def match_houid(prefix) match(/#{prefix}_[a-zA-Z0-9]{22}/) end end diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb index 28bea2bb8..cfdf6cd87 100644 --- a/spec/support/factory_bot.rb +++ b/spec/support/factory_bot.rb @@ -1,13 +1,13 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module FactoryBotExtensions - def force_create(name, *array_args, **args) - v = build(name, *array_args, **args) - v.save(validate:false) - v - end + def force_create(name, *array_args, **args) + v = build(name, *array_args, **args) + v.save(validate: false) + v + end end RSpec.configure do |config| - config.include FactoryBot::Syntax::Methods - config.include FactoryBotExtensions + config.include FactoryBot::Syntax::Methods + config.include FactoryBotExtensions end diff --git a/spec/support/init_dotenv.rb b/spec/support/init_dotenv.rb index 693148999..889cbc5b4 100644 --- a/spec/support/init_dotenv.rb +++ b/spec/support/init_dotenv.rb @@ -1,3 +1,3 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'dotenv' -Dotenv.load \ No newline at end of file +require "dotenv" +Dotenv.load diff --git a/spec/support/mock_helpers.rb b/spec/support/mock_helpers.rb index 45698a1f2..d193206bc 100644 --- a/spec/support/mock_helpers.rb +++ b/spec/support/mock_helpers.rb @@ -1,16 +1,16 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later module MockHelpers - def self.payment_export_headers() - ["Date",'Gross Amount', 'Fee Total', 'Net Amount','Type', 'Last Name', 'First Name', 'Just First Name', 'Full Name', 'Organization', 'Email', 'Phone', 'Address', 'City', 'State', 'Postal Code', 'Country', 'Supporter Id', 'Designation', "Dedication Type", - "Dedicated To: Name", - "Dedicated To: Supporter Id", - "Dedicated To: Email", - "Dedicated To: Phone", - "Dedicated To: Address", - "Dedicated To: Note", 'Anonymous?', 'Comment','Campaign', 'Campaign Id', 'Campaign Creator Email', 'Campaign Gift Level', 'Event Name', 'Payment', 'Check Number', 'Donation Note', 'Recurring Donation Started At', "Fee Covered By Supporter"] + def self.payment_export_headers + ["Date", "Gross Amount", "Fee Total", "Net Amount", "Type", "Last Name", "First Name", "Just First Name", "Full Name", "Organization", "Email", "Phone", "Address", "City", "State", "Postal Code", "Country", "Supporter Id", "Designation", "Dedication Type", + "Dedicated To: Name", + "Dedicated To: Supporter Id", + "Dedicated To: Email", + "Dedicated To: Phone", + "Dedicated To: Address", + "Dedicated To: Note", "Anonymous?", "Comment", "Campaign", "Campaign Id", "Campaign Creator Email", "Campaign Gift Level", "Event Name", "Payment", "Check Number", "Donation Note", "Recurring Donation Started At", "Fee Covered By Supporter"] end - def self.recurring_donation_export_headers() + def self.recurring_donation_export_headers ["Created At", "Amount", "Interval", @@ -25,21 +25,21 @@ def self.recurring_donation_export_headers() "Zip Code", "Card Name", "Recurring Donation Id", - "Donation Id", + "Donation Id", "Designation", "Fee Covered By Supporter", - "Status", - "Cancelled At", + "Status", + "Cancelled At", "Donation Management Url", - "Paydate", + "Paydate", "Last Charge Succeeded"] end def self.recurring_donation_export_headers_with_last_failed_charge - self.recurring_donation_export_headers.push("Last Failed Charge") + recurring_donation_export_headers.push("Last Failed Charge") end def self.generate_expected_rd_management_url(root_url, rd) "#{root_url}/recurring_donations/#{rd.id}/edit?t=#{rd.edit_token}" end -end \ No newline at end of file +end diff --git a/spec/support/payments_for_a_payout.rb b/spec/support/payments_for_a_payout.rb index ae748ac24..c15962354 100644 --- a/spec/support/payments_for_a_payout.rb +++ b/spec/support/payments_for_a_payout.rb @@ -1,6 +1,5 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -shared_context 'payments for a payout' do - +shared_context "payments for a payout" do class BalanceChangeExpectation include ActiveModel::AttributeAssignment @@ -18,13 +17,12 @@ class BalanceChangeExpectation # how many payments are pending or available associated with this balance change attr_accessor :count - # the primary entity associated with this balance change # For a dispute, this would be the dispute itself even though there's also an associated charge with this. attr_accessor :entity - def initialize(params={}) + def initialize(params = {}) assign_attributes(params) end @@ -34,10 +32,10 @@ def net_amount end end - let(:today) { Time.new(2020,5,5, 1) } - let(:yesterday) {Time.new(2020,5,4, 1)} - let(:two_days_ago) {Time.new(2020,5,3, 1)} - + let(:today) { Time.new(2020, 5, 5, 1) } + let(:yesterday) { Time.new(2020, 5, 4, 1) } + let(:two_days_ago) { Time.new(2020, 5, 3, 1) } + # let(:all_payments) { # payment_with_charge_to_output # partial_refunded_payment @@ -49,25 +47,25 @@ def net_amount # paid_out_dispute # other_np_payment # } - let(:eb_two_days_ago) {EntityBuilder.new(two_days_ago, nonprofit)} - let(:entities_two_days_ago){eb_two_days_ago.entities} - let(:payments_two_days_ago){eb_two_days_ago.payments} - let(:available_payments_two_days_ago) { eb_two_days_ago.available_payments} + let(:eb_two_days_ago) { EntityBuilder.new(two_days_ago, nonprofit) } + let(:entities_two_days_ago) { eb_two_days_ago.entities } + let(:payments_two_days_ago) { eb_two_days_ago.payments } + let(:available_payments_two_days_ago) { eb_two_days_ago.available_payments } - let(:eb_yesterday) {EntityBuilder.new(yesterday, nonprofit) } - let(:entities_yesterday) {eb_yesterday.entities} - let(:payments_yesterday){eb_yesterday.payments} - let(:available_payments_yesterday) { eb_yesterday.available_payments} + let(:eb_yesterday) { EntityBuilder.new(yesterday, nonprofit) } + let(:entities_yesterday) { eb_yesterday.entities } + let(:payments_yesterday) { eb_yesterday.payments } + let(:available_payments_yesterday) { eb_yesterday.available_payments } - let(:eb_today) {EntityBuilder.new(today, nonprofit) } - let(:entities_today) {eb_today.entities} - let(:payments_today) {eb_today.payments} - let(:available_payments_today) { eb_today.available_payments} + let(:eb_today) { EntityBuilder.new(today, nonprofit) } + let(:entities_today) { eb_today.entities } + let(:payments_today) { eb_today.payments } + let(:available_payments_today) { eb_today.available_payments } class EntityBuilder include FactoryBot::Syntax::Methods include FactoryBotExtensions - def initialize(time, nonprofit, other_nonprofit=nil) + def initialize(time, nonprofit, other_nonprofit = nil) @time = time @nonprofit = nonprofit @@ -77,29 +75,29 @@ def initialize(time, nonprofit, other_nonprofit=nil) def stats { - gross_amount: @inner_entities.map{|k,v| v.gross_amount}.sum, - fee_total: @inner_entities.map{|k,v| v.fee_total}.sum, - net_amount: @inner_entities.map{|k,v| v.net_amount}.sum, - pending_gross: @inner_entities.map{|k,v| v.pending_gross}.sum, - pending_net: @inner_entities.map{|k,v| v.pending_net}.sum, - count: @inner_entities.map{|k,v| v.count}.sum + gross_amount: @inner_entities.map { |k, v| v.gross_amount }.sum, + fee_total: @inner_entities.map { |k, v| v.fee_total }.sum, + net_amount: @inner_entities.map { |k, v| v.net_amount }.sum, + pending_gross: @inner_entities.map { |k, v| v.pending_gross }.sum, + pending_net: @inner_entities.map { |k, v| v.pending_net }.sum, + count: @inner_entities.map { |k, v| v.count }.sum } end def entities - @inner_entities.map{|k,v| [k, v.entity]}.to_h + @inner_entities.map { |k, v| [k, v.entity] }.to_h end def payments - entities.map do |k,v| + entities.map do |k, v| output = nil - if (v.is_a? Charge) + if v.is_a? Charge output = [v.payment] - elsif (v.is_a? Refund) + elsif v.is_a? Refund output = [v.payment, v.charge.payment] - elsif (v.is_a? Dispute) - output = v.dispute_transactions.map{|dt| dt.payment}.concat([v.charge.payment]) - elsif (v.is_a? ManualBalanceAdjustment) + elsif v.is_a? Dispute + output = v.dispute_transactions.map { |dt| dt.payment }.concat([v.charge.payment]) + elsif v.is_a? ManualBalanceAdjustment output = [v.payment, v.entity.payment] end @@ -108,38 +106,39 @@ def payments end def available_payments - entities.map do |k,v| + entities.map do |k, v| output = [] - if (v.is_a?(Charge) && v.status == 'available') - output << v.payment - elsif (v.is_a? Refund) + if v.is_a?(Charge) && v.status == "available" + output << v.payment + elsif v.is_a? Refund if !v.disbursed output << v.payment end - if (v.charge.status == 'available') + if v.charge.status == "available" output << v.charge.payment end - elsif (v.is_a? Dispute) - if (v.charge.status == 'available') + elsif v.is_a? Dispute + if v.charge.status == "available" output << v.charge.payment end - output = output.concat(v.dispute_transactions.select{|i| !i.disbursed}.map{|dt|dt.payment}) + output = output.concat(v.dispute_transactions.select { |i| !i.disbursed }.map { |dt| dt.payment }) - elsif (v.is_a? ManualBalanceAdjustment) + elsif v.is_a? ManualBalanceAdjustment - if (v.entity.status == 'available') + if v.entity.status == "available" output << v.entity.payment end if !v.disbursed output << v.payment end end - + output end.flatten.uniq end private + def build_entities output = {} Timecop.freeze(@time) do @@ -164,8 +163,8 @@ def build_entities end output end - - #net 100 + + # net 100 def charge_available BalanceChangeExpectation.new( gross_amount: 100, @@ -173,8 +172,8 @@ def charge_available pending_net: 0, pending_gross: 0, count: 1, - entity: charge_create(gross_amount:100, status: 'available')) - + entity: charge_create(gross_amount: 100, status: "available") + ) end # net 0 @@ -185,19 +184,20 @@ def charge_paid pending_net: 0, pending_gross: 0, count: 0, - entity:charge_create(gross_amount:200, status: 'paid') + entity: charge_create(gross_amount: 200, status: "paid") ) end # 450 pending - def charge_pending + def charge_pending BalanceChangeExpectation.new( gross_amount: 0, fee_total: 0, pending_net: 350, pending_gross: 400, count: 1, - entity:charge_create(gross_amount:400, fee_total: -50, status: 'pending')) + entity: charge_create(gross_amount: 400, fee_total: -50, status: "pending") + ) end # net 0 @@ -208,23 +208,25 @@ def refund_disbursed pending_net: 0, pending_gross: 0, count: 0, - entity: refund_create({gross_amount:800, original_charge_args: {status: 'paid'}, disbursed: true})) + entity: refund_create({gross_amount: 800, original_charge_args: {status: "paid"}, disbursed: true}) + ) end # net 0 def refund BalanceChangeExpectation.new( - gross_amount: 0, - fee_total: 0, + gross_amount: 0, + fee_total: 0, pending_net: 0, pending_gross: 0, count: 2, - entity:refund_create({gross_amount:1600, original_charge_args:{status: 'available'}})) + entity: refund_create({gross_amount: 1600, original_charge_args: {status: "available"}}) + ) end # net 0 def legacy_dispute_paid - d= dispute_create(gross_amount:3200, status: :lost, original_charge_args: {status: 'paid'}) + d = dispute_create(gross_amount: 3200, status: :lost, original_charge_args: {status: "paid"}) d.dispute_transactions.create(**dispute_transaction_args_create(-3200, 0), disbursed: true) BalanceChangeExpectation.new( gross_amount: 0, @@ -232,24 +234,26 @@ def legacy_dispute_paid pending_net: 0, pending_gross: 0, count: 0, - entity: d) + entity: d + ) end # net 6400 def legacy_dispute_won - d = dispute_create(gross_amount:6400, status: :won) + d = dispute_create(gross_amount: 6400, status: :won) BalanceChangeExpectation.new( - gross_amount: 6400, + gross_amount: 6400, fee_total: 0, pending_net: 0, pending_gross: 0, count: 1, - entity: d) + entity: d + ) end # net 0 def legacy_dispute_lost - d = dispute_create(gross_amount:25600, status: :lost) + d = dispute_create(gross_amount: 25600, status: :lost) d.dispute_transactions.create(**dispute_transaction_args_create(-25600, 0)) BalanceChangeExpectation.new( gross_amount: 0, @@ -257,12 +261,13 @@ def legacy_dispute_lost pending_net: 0, pending_gross: 0, count: 1, - entity: d) + entity: d + ) end - + # net -1500 def dispute_lost - d = dispute_create(gross_amount:12800, status: :lost) + d = dispute_create(gross_amount: 12800, status: :lost) d.dispute_transactions.create(**dispute_transaction_args_create(-12800, -1500)) BalanceChangeExpectation.new( gross_amount: 0, @@ -270,7 +275,8 @@ def dispute_lost pending_net: 0, pending_gross: 0, count: 2, - entity: d) + entity: d + ) end # net 51200 @@ -278,44 +284,46 @@ def dispute_won d = dispute_create({gross_amount: 51200, status: :won}) d.dispute_transactions.create(**dispute_transaction_args_create(-51200, -1500)) d.dispute_transactions.create(**dispute_transaction_args_create(51200, 1500)) - + BalanceChangeExpectation.new( - gross_amount: 51200, + gross_amount: 51200, fee_total: 0, pending_net: 0, pending_gross: 0, count: 3, - entity: d) + entity: d + ) end # net 0 def dispute_paid - d = dispute_create(gross_amount:102800, status: :lost, original_charge_args: {status: :paid}) + d = dispute_create(gross_amount: 102800, status: :lost, original_charge_args: {status: :paid}) d.dispute_transactions.create(disbursed: true, **dispute_transaction_args_create(-102800, -1500)) - BalanceChangeExpectation.new(gross_amount: 0, - fee_total: 0, - pending_net: 0, - pending_gross: 0, - count: 0, - entity: d) + BalanceChangeExpectation.new(gross_amount: 0, + fee_total: 0, + pending_net: 0, + pending_gross: 0, + count: 0, + entity: d) end # net -1500 def dispute_under_review - d = dispute_create(gross_amount:205600, status: :under_review) + d = dispute_create(gross_amount: 205600, status: :under_review) d.dispute_transactions.create(**dispute_transaction_args_create(-205600, -1500)) BalanceChangeExpectation.new( gross_amount: 0, fee_total: -1500, pending_net: 0, pending_gross: 0, - count:2, - entity: d) + count: 2, + entity: d + ) end # net -1500 def dispute_needs_response - d = dispute_create(gross_amount:512000, status: :needs_response) + d = dispute_create(gross_amount: 512000, status: :needs_response) d.dispute_transactions.create(**dispute_transaction_args_create(-512000, -1500)) BalanceChangeExpectation.new( gross_amount: 0, @@ -323,73 +331,73 @@ def dispute_needs_response pending_net: 0, pending_gross: 0, count: 2, - entity: d) + entity: d + ) end # gross 100, net -350, fee_total: -450 def manual_balance_adjustment - adj = manual_balance_adjustment_create(gross_amount: 0, fee_total: -400, charge_args: {gross_amount: 100, fee_total: -50, status:'available'}) + adj = manual_balance_adjustment_create(gross_amount: 0, fee_total: -400, charge_args: {gross_amount: 100, fee_total: -50, status: "available"}) BalanceChangeExpectation.new( gross_amount: 100, fee_total: -450, pending_net: 0, pending_gross: 0, count: 2, - entity: adj) + entity: adj + ) end # gross 100, net 50, fee_total -50 def manual_balance_adjustment_disbursed - adj = manual_balance_adjustment_create(gross_amount: 0, fee_total: -400, disbursed: true, charge_args: {gross_amount: 100, fee_total: -50, status:'available'}) + adj = manual_balance_adjustment_create(gross_amount: 0, fee_total: -400, disbursed: true, charge_args: {gross_amount: 100, fee_total: -50, status: "available"}) BalanceChangeExpectation.new( gross_amount: 100, fee_total: -50, pending_net: 0, pending_gross: 0, count: 1, - entity: adj) + entity: adj + ) end - - def refund_create(args={}) - fee_total = args[:fee_total] || 0 + def refund_create(args = {}) + args[:fee_total] || 0 gross_amount = args[:gross_amount] fee_total = args[:fee_total] || 0 - - temp_charge_args = {gross_amount:gross_amount, fee_total: fee_total } - temp_charge_args = temp_charge_args.merge(args[:original_charge_args]) if args[:original_charge_args] + temp_charge_args = {gross_amount: gross_amount, fee_total: fee_total} + temp_charge_args = temp_charge_args.merge(args[:original_charge_args]) if args[:original_charge_args] - orig_charge = charge_create(status: 'available', **temp_charge_args) + orig_charge = charge_create(status: "available", **temp_charge_args) - force_create(:refund, amount: args[:gross_amount], charge: orig_charge, payment: payment_create( gross_amount:-1 * gross_amount, fee_total: fee_total || 0, net_amount: (-1 * gross_amount) - fee_total), **args.except(:gross_amount, :original_charge_args)) + force_create(:refund, amount: args[:gross_amount], charge: orig_charge, payment: payment_create(gross_amount: -1 * gross_amount, fee_total: fee_total || 0, net_amount: (-1 * gross_amount) - fee_total), **args.except(:gross_amount, :original_charge_args)) end - def dispute_create(args={}) + def dispute_create(args = {}) gross_amount = args[:gross_amount] - temp_charge_args = {gross_amount:gross_amount } + temp_charge_args = {gross_amount: gross_amount} temp_charge_args = temp_charge_args.merge(args[:original_charge_args]) if args[:original_charge_args] - orig_charge = charge_create(status: 'available', **temp_charge_args) + orig_charge = charge_create(status: "available", **temp_charge_args) force_create(:dispute, :autocreate_dispute, gross_amount: gross_amount, charge: orig_charge, **args.except(:original_charge_args)) end def dispute_transaction_args_create(gross_amount, fee_total) - {gross_amount: gross_amount, fee_total: fee_total, - payment: payment_create(gross_amount:gross_amount, fee_total: fee_total, net_amount: gross_amount + fee_total, - nonprofit: @nonprofit )} + {gross_amount: gross_amount, fee_total: fee_total, + payment: payment_create(gross_amount: gross_amount, fee_total: fee_total, net_amount: gross_amount + fee_total, + nonprofit: @nonprofit)} end - def charge_create( args={}) + def charge_create(args = {}) gross_amount = args[:gross_amount] fee_total = args[:fee_total] || 0 other_args = args.except(:gross_amount, :fee_total) - force_create(:charge, nonprofit:@nonprofit, amount: gross_amount, + force_create(:charge, nonprofit: @nonprofit, amount: gross_amount, payment: payment_create(gross_amount: gross_amount, fee_total: fee_total, net_amount: gross_amount + fee_total), **other_args) end - def manual_balance_adjustment_create(args={}) - + def manual_balance_adjustment_create(args = {}) gross_amount = args[:gross_amount] fee_total = args[:fee_total] || 0 charge_args = args[:charge_args] @@ -399,14 +407,11 @@ def manual_balance_adjustment_create(args={}) gross_amount: gross_amount, fee_total: fee_total, payment: payment_create(gross_amount: gross_amount, fee_total: fee_total, net_amount: gross_amount + fee_total), - entity: charge_create(charge_args), **args ) - + entity: charge_create(charge_args), **args) end - def payment_create(args={}) - force_create(:payment, nonprofit:@nonprofit, date: @time, **args) + def payment_create(args = {}) + force_create(:payment, nonprofit: @nonprofit, date: @time, **args) end - - end -end \ No newline at end of file +end diff --git a/spec/support/stripe_mock_helper.rb b/spec/support/stripe_mock_helper.rb index d6dbb838f..23a0d600a 100644 --- a/spec/support/stripe_mock_helper.rb +++ b/spec/support/stripe_mock_helper.rb @@ -1,26 +1,22 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later - # StripeMockHelper wraps the StripeMock to simplify creating a single test helper as part of # a test session. Generally, you can use StripeMockHelper like StripeMock except it adds a "default_helper" # to get the StripeTestHelper for the session. # @see StripeMock StripeMockHelper = Class.new do - delegate_missing_to :StripeMock # Most StripeMock sessions only need a single test helper so you can get it here # @return a Stripe test helper or nil if none is set def default_helper if defined? @default_helper - @default_helper - else - nil + @default_helper end end alias_method :stripe_helper, :default_helper - + # sets up a StripeMock session and sets up StripeMock::default_helper # note: Rspec is set up to autostop a StripeMock session when an example finishes def start @@ -41,20 +37,19 @@ def mock(&block) start block.call - + stop end private - + # Clears the default test helper for the current StripeMock session def clear_default_helper remove_instance_variable :@default_helper if defined? @default_helper end - + # Creates a default test helper for the current StripeMock session def create_default_helper @default_helper ||= StripeMock.create_test_helper end end.new - \ No newline at end of file diff --git a/spec/support/test/stripe_mock_helper_spec.rb b/spec/support/test/stripe_mock_helper_spec.rb index 1d2d340c4..e59f12144 100644 --- a/spec/support/test/stripe_mock_helper_spec.rb +++ b/spec/support/test/stripe_mock_helper_spec.rb @@ -1,29 +1,29 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' +require "rails_helper" -describe StripeMockHelper do - it 'sets stripe_helper' do +describe StripeMockHelper do + it "sets stripe_helper" do expect(StripeMockHelper.stripe_helper).to be_falsy StripeMockHelper.mock do expect(StripeMockHelper.stripe_helper).to be_truthy end end - it 'clears stripe_helper when finished' do + it "clears stripe_helper when finished" do StripeMockHelper.mock do end expect(StripeMockHelper.stripe_helper).to be_falsy end describe "#start" do - it 'is safely reentrant' do + it "is safely reentrant" do StripeMockHelper.mock do # products are now required in plans as of Stripe gem 5.0 product = StripeMockHelper.stripe_helper.create_product # create a plan - StripeMockHelper.stripe_helper.create_plan(id: 'test_str_plan', amount: 0, currency: 'usd', interval: 'year', name: 'test PLan', product: product.id) + StripeMockHelper.stripe_helper.create_plan(id: "test_str_plan", amount: 0, currency: "usd", interval: "year", name: "test PLan", product: product.id) StripeMockHelper.start - expect { Stripe::Plan.retrieve('test_str_plan')}.to_not(raise_error, "If this object is not available, \ + expect { Stripe::Plan.retrieve("test_str_plan") }.to_not(raise_error, "If this object is not available, \ then the StripeMockHelper.start is incorrectly creating a new StripeMock session") end end diff --git a/spec/support/test_chunked_uploader.rb b/spec/support/test_chunked_uploader.rb index 88209d23b..799c643a6 100644 --- a/spec/support/test_chunked_uploader.rb +++ b/spec/support/test_chunked_uploader.rb @@ -1,6 +1,6 @@ # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later class TestChunkedUploader - TEST_ERROR_MESSAGE = 'test exception thrown' + TEST_ERROR_MESSAGE = "test exception thrown" def self.clear @@output = nil @@raise_error = false @@ -10,6 +10,7 @@ def self.clear def self.output @@output end + ## use this to throw an exception instead of finishing def self.raise_error @@raise_error = true @@ -19,16 +20,16 @@ def self.options @@options end - def self.upload(path,chunk_enum, options={}) + def self.upload(path, chunk_enum, options = {}) @@options = options - io = StringIO.new('', 'w') - chunk_enum.each do |chunk| + io = StringIO.new("", "w") + chunk_enum.each do |chunk| io.write(chunk) end - if (@@raise_error) + if @@raise_error raise TEST_ERROR_MESSAGE end @@output = io.string - 'http://fake.url/' + path + "http://fake.url/" + path end -end \ No newline at end of file +end diff --git a/spec/tasks/js_spec.rb b/spec/tasks/js_spec.rb index 46f69e1e1..665f5dd4c 100644 --- a/spec/tasks/js_spec.rb +++ b/spec/tasks/js_spec.rb @@ -2,55 +2,55 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" Rails.application.load_tasks -describe 'js.rake' do # rubocop:disable RSpec/DescribeClass - def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") - end - - let(:js_dir) { Rails.root.join('app/javascript') } - - def wrap_task(rake_taskname) - task = Rake::Task[rake_taskname] - Rake.application.tasks.each(&:reenable) - task.invoke - yield - Rake.application.tasks.each(&:reenable) - end - - def verify_cleaned(rake_taskname) # rubocop:disable Metrics/AbcSize - wrap_task(rake_taskname) do - expect(!File.exist?(js_dir.join('routes.js'))).to( - be(true), - "#{js_dir.join('routes.js')} wasn't cleaned by bin/rails #{rake_taskname}" - ) - - expect(!File.exist?(js_dir.join('routes.d.ts'))).to( - be(true), - "#{js_dir.join('routes.d.ts')} wasn't cleaned by bin/rails #{rake_taskname}" - ) - end - end - - def verify_task_generate(rake_taskname) - wrap_task(rake_taskname) do - expect(File.exist?(js_dir.join('routes.js'))).to( - be(true), - "#{js_dir.join('routes.js')} wasn't generated by bin/rails #{rake_taskname}" - ) - - expect(File.exist?(js_dir.join('routes.d.ts'))).to( - be(true), - "#{js_dir.join('routes.d.ts')} wasn't generated by bin/rails #{rake_taskname}" - ) - end - end - - it 'export and clean' do # rubocop:disable RSpec/NoExpectationExample - verify_task_generate('js:routes:typescript') - verify_cleaned('js:routes:clean') - end +describe "js.rake" do # rubocop:disable RSpec/DescribeClass + def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") + end + + let(:js_dir) { Rails.root.join("app/javascript") } + + def wrap_task(rake_taskname) + task = Rake::Task[rake_taskname] + Rake.application.tasks.each(&:reenable) + task.invoke + yield + Rake.application.tasks.each(&:reenable) + end + + def verify_cleaned(rake_taskname) # rubocop:disable Metrics/AbcSize + wrap_task(rake_taskname) do + expect(!File.exist?(js_dir.join("routes.js"))).to( + be(true), + "#{js_dir.join("routes.js")} wasn't cleaned by bin/rails #{rake_taskname}" + ) + + expect(!File.exist?(js_dir.join("routes.d.ts"))).to( + be(true), + "#{js_dir.join("routes.d.ts")} wasn't cleaned by bin/rails #{rake_taskname}" + ) + end + end + + def verify_task_generate(rake_taskname) + wrap_task(rake_taskname) do + expect(File.exist?(js_dir.join("routes.js"))).to( + be(true), + "#{js_dir.join("routes.js")} wasn't generated by bin/rails #{rake_taskname}" + ) + + expect(File.exist?(js_dir.join("routes.d.ts"))).to( + be(true), + "#{js_dir.join("routes.d.ts")} wasn't generated by bin/rails #{rake_taskname}" + ) + end + end + + it "export and clean" do # rubocop:disable RSpec/NoExpectationExample + verify_task_generate("js:routes:typescript") + verify_cleaned("js:routes:clean") + end end diff --git a/spec/views/api_new/offline_transaction_charges/show.json.jbuilder_spec.rb b/spec/views/api_new/offline_transaction_charges/show.json.jbuilder_spec.rb index f592be925..75d8051ef 100644 --- a/spec/views/api_new/offline_transaction_charges/show.json.jbuilder_spec.rb +++ b/spec/views/api_new/offline_transaction_charges/show.json.jbuilder_spec.rb @@ -2,36 +2,35 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" -RSpec.describe '/api_new/offline_transaction_charges/show.json.jbuilder', type: :view do - let(:transaction) { create(:transaction_for_offline_donation) } - let(:offline_transaction_charge) { transaction.subtransaction.subtransaction_payments.first.offline_transaction_charge } +RSpec.describe "/api_new/offline_transaction_charges/show.json.jbuilder", type: :view do + let(:transaction) { create(:transaction_for_offline_donation) } + let(:offline_transaction_charge) { transaction.subtransaction.subtransaction_payments.first.offline_transaction_charge } - subject(:json) do - view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) - assign(:offline_transaction_charge, offline_transaction_charge) - render - rendered - end + subject(:json) do + view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) + assign(:offline_transaction_charge, offline_transaction_charge) + render + rendered + end - it { - is_expected.to include_json(object: 'offline_transaction_charge', - created: offline_transaction_charge.created.to_i, - kind: offline_transaction_charge.subtransaction_payment.legacy_payment.offsite_payment&.kind, - check_number: offline_transaction_charge.subtransaction_payment.legacy_payment.offsite_payment&.check_number, - net_amount: { - cents: offline_transaction_charge.net_amount_as_money.cents, - currency: 'usd', - }, - gross_amount: { - cents: offline_transaction_charge.gross_amount_as_money.cents, - currency: 'usd', - }, - fee_total: { - cents: offline_transaction_charge.fee_total_as_money.cents, - currency: 'usd', - } - ) - } + it { + is_expected.to include_json(object: "offline_transaction_charge", + created: offline_transaction_charge.created.to_i, + kind: offline_transaction_charge.subtransaction_payment.legacy_payment.offsite_payment&.kind, + check_number: offline_transaction_charge.subtransaction_payment.legacy_payment.offsite_payment&.check_number, + net_amount: { + cents: offline_transaction_charge.net_amount_as_money.cents, + currency: "usd" + }, + gross_amount: { + cents: offline_transaction_charge.gross_amount_as_money.cents, + currency: "usd" + }, + fee_total: { + cents: offline_transaction_charge.fee_total_as_money.cents, + currency: "usd" + }) + } end diff --git a/spec/views/api_new/payouts/show.json.jbuilder_spec.rb b/spec/views/api_new/payouts/show.json.jbuilder_spec.rb index f4398c479..e570d52d2 100644 --- a/spec/views/api_new/payouts/show.json.jbuilder_spec.rb +++ b/spec/views/api_new/payouts/show.json.jbuilder_spec.rb @@ -2,9 +2,9 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" -RSpec.describe '/api_new/payouts/show.json.jbuilder', type: :view do +RSpec.describe "/api_new/payouts/show.json.jbuilder", type: :view do let(:payout) { build(:payout, nonprofit: build(:nonprofit)) } subject(:json) do view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) @@ -14,14 +14,13 @@ end it do - is_expected.to include_json(id: payout.houid, - created: payout.created_at.to_i, - net_amount: { - cents: payout.net_amount_as_money.cents, - currency: 'usd', - }, - status: payout.status, - object: 'payout' - ) + is_expected.to include_json(id: payout.houid, + created: payout.created_at.to_i, + net_amount: { + cents: payout.net_amount_as_money.cents, + currency: "usd" + }, + status: payout.status, + object: "payout") end -end \ No newline at end of file +end diff --git a/spec/views/api_new/supporters/show.json.jbuilder_spec.rb b/spec/views/api_new/supporters/show.json.jbuilder_spec.rb index 49371acd4..6dc15cd56 100644 --- a/spec/views/api_new/supporters/show.json.jbuilder_spec.rb +++ b/spec/views/api_new/supporters/show.json.jbuilder_spec.rb @@ -2,99 +2,99 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' - -RSpec.describe '/api_new/supporters/show.json.jbuilder', type: :view do - subject(:json) do - view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) - assign(:supporter, supporter) - render - JSON.parse(rendered) - end - - let(:supporter) { create(:supporter_with_fv_poverty, :with_primary_address) } - let(:id) { json['id'] } - let(:nonprofit) { supporter.nonprofit } - - it { - is_expected.to include('object' => 'supporter') - } - - it { - is_expected.to include('id' => supporter.houid) - } - - it { - is_expected.to include('legacy_id' => supporter.id) - } - - it { - is_expected.to include('name' => 'Fake Supporter Name') - } - - it { - is_expected.to include('legacy_nonprofit' => nonprofit.id) - } - - it { - is_expected.to include('nonprofit' => nonprofit.houid) - } - - it { - is_expected.to include('anonymous' => false) - } - - it { - is_expected.to include('deleted' => false) - } - - it { - is_expected.to include('merged_into' => nil) - } - - it { - is_expected.to include('organization' => nil) - } - - it { - is_expected.to include('phone' => nil) - } - - it { - is_expected.to include('email' => supporter.email) - } - - describe 'supporter_addresses' do - subject(:addresses) {json['supporter_addresses']} - it { - expect(addresses.count).to eq 1 - } - describe ' with the only address' do - subject(:sole_address) { addresses.first} - it { - is_expected.to include('address' => supporter.address) - } - - it { - is_expected.to include('city' => supporter.city) - } - - it { - is_expected.to include('state_code' => supporter.state_code) - } - - it { - is_expected.to include('zip_code' => supporter.zip_code) - } - - it { - is_expected.to include('country' => supporter.country) - } - end - end - - # it { - # is_expected.to include('url' => - # a_string_matching(%r{http://test\.host/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}})) - # } +require "rails_helper" + +RSpec.describe "/api_new/supporters/show.json.jbuilder", type: :view do + subject(:json) do + view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) + assign(:supporter, supporter) + render + JSON.parse(rendered) + end + + let(:supporter) { create(:supporter_with_fv_poverty, :with_primary_address) } + let(:id) { json["id"] } + let(:nonprofit) { supporter.nonprofit } + + it { + is_expected.to include("object" => "supporter") + } + + it { + is_expected.to include("id" => supporter.houid) + } + + it { + is_expected.to include("legacy_id" => supporter.id) + } + + it { + is_expected.to include("name" => "Fake Supporter Name") + } + + it { + is_expected.to include("legacy_nonprofit" => nonprofit.id) + } + + it { + is_expected.to include("nonprofit" => nonprofit.houid) + } + + it { + is_expected.to include("anonymous" => false) + } + + it { + is_expected.to include("deleted" => false) + } + + it { + is_expected.to include("merged_into" => nil) + } + + it { + is_expected.to include("organization" => nil) + } + + it { + is_expected.to include("phone" => nil) + } + + it { + is_expected.to include("email" => supporter.email) + } + + describe "supporter_addresses" do + subject(:addresses) { json["supporter_addresses"] } + it { + expect(addresses.count).to eq 1 + } + describe " with the only address" do + subject(:sole_address) { addresses.first } + it { + is_expected.to include("address" => supporter.address) + } + + it { + is_expected.to include("city" => supporter.city) + } + + it { + is_expected.to include("state_code" => supporter.state_code) + } + + it { + is_expected.to include("zip_code" => supporter.zip_code) + } + + it { + is_expected.to include("country" => supporter.country) + } + end + end + + # it { + # is_expected.to include('url' => + # a_string_matching(%r{http://test\.host/api_new/nonprofits/#{nonprofit.houid}/supporters/#{supporter.houid}})) + # } end diff --git a/spec/views/api_new/transactions/index.json.jbuilder_spec.rb b/spec/views/api_new/transactions/index.json.jbuilder_spec.rb index 7a5d74922..ec90a9c4e 100644 --- a/spec/views/api_new/transactions/index.json.jbuilder_spec.rb +++ b/spec/views/api_new/transactions/index.json.jbuilder_spec.rb @@ -2,103 +2,100 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" -RSpec.describe '/api_new/transactions/index.json.jbuilder', type: :view do +RSpec.describe "/api_new/transactions/index.json.jbuilder", type: :view do + around do |ex| + Timecop.freeze(2020, 5, 4) do + ex.run + end + end - around do |ex| - Timecop.freeze(2020, 5, 4) do - ex.run - end - end + include Controllers::ApiNew::JbuilderExpansions + def base_path(nonprofit_id, transaction_id) + "/api_new/nonprofits/#{nonprofit_id}/transactions/#{transaction_id}" + end - include Controllers::ApiNew::JbuilderExpansions - def base_path(nonprofit_id, transaction_id) - "/api_new/nonprofits/#{nonprofit_id}/transactions/#{transaction_id}" - end + def base_url(nonprofit_id, transaction_id) + "http://test.host#{base_path(nonprofit_id, transaction_id)}" + end - def base_url(nonprofit_id, transaction_id) - "http://test.host#{base_path(nonprofit_id, transaction_id)}" - end + subject(:json) do + view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace + assign(:transactions, Kaminari.paginate_array([transaction]).page) + assign(:__expand, Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new("supporter", "transaction_assignments", "payments", "subtransaction.payments")) + render + rendered + end - subject(:json) do - view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace - assign(:transactions, Kaminari.paginate_array([transaction]).page) - assign(:__expand, Controllers::ApiNew::JbuilderExpansions::ExpansionTree.new('supporter', 'transaction_assignments', 'payments', 'subtransaction.payments')) - render - rendered - end + let(:transaction) { create(:transaction_for_offline_donation) } + let(:supporter) { transaction.supporter } + let(:nonprofit) { transaction.nonprofit } - let(:transaction) { create(:transaction_for_offline_donation) } - let(:supporter) { transaction.supporter } - let(:nonprofit) { transaction.nonprofit } + it { + is_expected.to include_json( + "first_page" => true, + :last_page => true, + :current_page => 1, + :requested_size => 25, + :total_count => 1, + :data => [ + attributes_for(:trx, + nonprofit: nonprofit.houid, + supporter: attributes_for( + :supporter_expectation, + id: supporter.houid + ), + id: transaction.houid, + amount_cents: 4000, + subtransaction: attributes_for( + :subtransaction_expectation, + :offline_transaction, + gross_amount_cents: 4000, + net_amount_cents: 4000, + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ] + ), + payments: [ + attributes_for(:payment_expectation, + :offline_transaction_charge, + gross_amount_cents: 4000, + fee_total_cents: 0) + ], + transaction_assignments: [ + attributes_for(:trx_assignment_expectation, + :donation, + amount_cents: 4000, + designation: "Designation 1") + ]) + ] + ) + } - it { - is_expected.to include_json( - 'first_page' => true, - last_page: true, - current_page: 1, - requested_size: 25, - total_count: 1, - data: [ - attributes_for(:trx, - nonprofit: nonprofit.houid, - supporter: attributes_for( - :supporter_expectation, - id: supporter.houid - ), - id: transaction.houid, - amount_cents: 4000, - subtransaction: attributes_for( - :subtransaction_expectation, - :offline_transaction, - gross_amount_cents: 4000, - net_amount_cents: 4000, - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ] - ), - payments: [ - attributes_for(:payment_expectation, - :offline_transaction_charge, - gross_amount_cents: 4000, - fee_total_cents: 0) - ], - transaction_assignments: [ - attributes_for(:trx_assignment_expectation, - :donation, - amount_cents:4000, - designation: "Designation 1" - ) - ] - ) - ] - ) - } + # describe 'paging' do + # subject(:json) do + # transaction + # (0..5).each do |_i| + # create( + # :transaction, + # nonprofit: transaction.nonprofit, + # supporter: transaction.supporter + # ) + # end + # assign(:transactions, nonprofit.transactions.order('created DESC').page.per(5)) + # render + # JSON.parse(rendered) + # end - # describe 'paging' do - # subject(:json) do - # transaction - # (0..5).each do |_i| - # create( - # :transaction, - # nonprofit: transaction.nonprofit, - # supporter: transaction.supporter - # ) - # end - # assign(:transactions, nonprofit.transactions.order('created DESC').page.per(5)) - # render - # JSON.parse(rendered) - # end - - # it { is_expected.to include('data' => have_attributes(count: 5)) } - # it { is_expected.to include('first_page' => true) } - # it { is_expected.to include('last_page' => false) } - # it { is_expected.to include('current_page' => 1) } - # it { is_expected.to include('requested_size' => 5) } - # it { is_expected.to include('total_count' => 7) } - # end + # it { is_expected.to include('data' => have_attributes(count: 5)) } + # it { is_expected.to include('first_page' => true) } + # it { is_expected.to include('last_page' => false) } + # it { is_expected.to include('current_page' => 1) } + # it { is_expected.to include('requested_size' => 5) } + # it { is_expected.to include('total_count' => 7) } + # end end diff --git a/spec/views/api_new/users/current.json.jbuilder_spec.rb b/spec/views/api_new/users/current.json.jbuilder_spec.rb index e848469a0..4a57af36b 100644 --- a/spec/views/api_new/users/current.json.jbuilder_spec.rb +++ b/spec/views/api_new/users/current.json.jbuilder_spec.rb @@ -2,69 +2,61 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' - -RSpec.describe '/api_new/users/current.json.jbuilder', type: :view do - - context 'for user as nonprofit_admin' do - - subject(:json) do - view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace - assign(:user, create(:user_base, roles: [build(:role_base, :as_nonprofit_admin)])) - render - rendered - end - - - it { - is_expected.to include_json( - object: 'user', - is_super_admin: false, - roles: [ - { - host: Nonprofit.first.to_houid - } - ]) - } - - end - - context 'for user as nonprofit_associate' do - - subject(:json) do - view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace - assign(:user, create(:user_as_nonprofit_associate)) - render - rendered - end - - - it { - is_expected.to include_json( - object: 'user', - is_super_admin: false, - roles: []) - } - - end - - context 'for user as super_admin' do - - subject(:json) do - view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace - assign(:user, create(:user_as_super_admin)) - render - rendered - end - - - it { - is_expected.to include_json( - object: 'user', - is_super_admin: true, - roles: [] - ) - } - - end +require "rails_helper" + +RSpec.describe "/api_new/users/current.json.jbuilder", type: :view do + context "for user as nonprofit_admin" do + subject(:json) do + view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace + assign(:user, create(:user_base, roles: [build(:role_base, :as_nonprofit_admin)])) + render + rendered + end + + it { + is_expected.to include_json( + object: "user", + is_super_admin: false, + roles: [ + { + host: Nonprofit.first.to_houid + } + ] + ) + } + end + + context "for user as nonprofit_associate" do + subject(:json) do + view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace + assign(:user, create(:user_as_nonprofit_associate)) + render + rendered + end + + it { + is_expected.to include_json( + object: "user", + is_super_admin: false, + roles: [] + ) + } + end + + context "for user as super_admin" do + subject(:json) do + view.lookup_context.prefixes = view.lookup_context.prefixes.drop(2) # Rails does weird things in view specs when you use a route namespace + assign(:user, create(:user_as_super_admin)) + render + rendered + end + + it { + is_expected.to include_json( + object: "user", + is_super_admin: true, + roles: [] + ) + } + end end diff --git a/spec/views/event_discount/create.json.jbuilder_spec.rb b/spec/views/event_discount/create.json.jbuilder_spec.rb index 4e70ec05a..979fb8ddf 100644 --- a/spec/views/event_discount/create.json.jbuilder_spec.rb +++ b/spec/views/event_discount/create.json.jbuilder_spec.rb @@ -1,4 +1,4 @@ -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" RSpec.describe "event_discounts/create.json.jbuilder", type: :view do diff --git a/spec/views/event_discount/update.json.jbuilder_spec.rb b/spec/views/event_discount/update.json.jbuilder_spec.rb index e78778368..35abd931d 100644 --- a/spec/views/event_discount/update.json.jbuilder_spec.rb +++ b/spec/views/event_discount/update.json.jbuilder_spec.rb @@ -1,4 +1,4 @@ -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later require "rails_helper" RSpec.describe "event_discounts/update.json.jbuilder", type: :view do diff --git a/spec/views/mailchimp/list.json.jbuilder_spec.rb b/spec/views/mailchimp/list.json.jbuilder_spec.rb index 50f137c59..18291bb6b 100644 --- a/spec/views/mailchimp/list.json.jbuilder_spec.rb +++ b/spec/views/mailchimp/list.json.jbuilder_spec.rb @@ -2,13 +2,10 @@ # License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" -RSpec.describe '/mailchimp/list.json.jbuilder', type: :view do - - - describe 'supporter with no active recurring donations' do - +RSpec.describe "/mailchimp/list.json.jbuilder", type: :view do + describe "supporter with no active recurring donations" do subject(:json) do view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) assign(:supporter, create(:supporter, name: "Penelope Schultz")) @@ -16,22 +13,19 @@ rendered end - it { - is_expected.to include_json( - email_address: Supporter.first.email, - status: 'subscribed', + is_expected.to include_json( + email_address: Supporter.first.email, + status: "subscribed", merge_fields: { - F_NAME: 'Penelope', - L_NAME: 'Schultz' + F_NAME: "Penelope", + L_NAME: "Schultz" } ) - } + } end - # TODO: Fix this spec - describe 'supporter with active recurring donations', skip: 'TODO' do - + # TODO: Fix this spec + describe "supporter with active recurring donations", skip: "TODO" do end - -end \ No newline at end of file +end diff --git a/spec/views/mailchimp/nonprofit_user_subscribe.json.jbuilder_spec.rb b/spec/views/mailchimp/nonprofit_user_subscribe.json.jbuilder_spec.rb index c1216a05f..777c90261 100644 --- a/spec/views/mailchimp/nonprofit_user_subscribe.json.jbuilder_spec.rb +++ b/spec/views/mailchimp/nonprofit_user_subscribe.json.jbuilder_spec.rb @@ -1,26 +1,24 @@ # frozen_string_literal: true -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # Full license explanation at https://github.com/houdiniproject/houdini/blob/main/LICENSE -require 'rails_helper' +require "rails_helper" -RSpec.describe '/mailchimp/nonprofit_user_subscribe.json.jbuilder', type: :view do - - describe 'adding new subscriber to nonprofit list' do - - subject(:json) do +RSpec.describe "/mailchimp/nonprofit_user_subscribe.json.jbuilder", type: :view do + describe "adding new subscriber to nonprofit list" do + subject(:json) do view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) - user = create(:user_as_nonprofit_associate) + user = create(:user_as_nonprofit_associate) assign(:user, user) assign(:nonprofit, user.roles.first.host) render rendered - end + end it { is_expected.to include_json( email_address: User.first.email, - status: 'subscribed', + status: "subscribed", merge_fields: { NP_ID: User.first.roles.first.host.id, NP_SUPP: 0, @@ -29,20 +27,20 @@ ) } - describe 'provide first name' do - subject(:json) do + describe "provide first name" do + subject(:json) do view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) - user = create(:user_as_nonprofit_associate, :with_first_name) + user = create(:user_as_nonprofit_associate, :with_first_name) assign(:user, user) assign(:nonprofit, user.roles.first.host) render rendered - end - + end + it { is_expected.to include_json( email_address: User.first.email, - status: 'subscribed', + status: "subscribed", merge_fields: { NP_ID: User.first.roles.first.host.id, NP_SUPP: 0, @@ -52,22 +50,22 @@ } end - describe 'provide supporters' do - subject(:json) do + describe "provide supporters" do + subject(:json) do view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) user = create(:user_as_nonprofit_associate, :with_first_name) nonprofit = user.roles.first.host - supp = create(:supporter, nonprofit: nonprofit) + create(:supporter, nonprofit: nonprofit) assign(:user, user) assign(:nonprofit, user.roles.first.host) render rendered - end - + end + it { is_expected.to include_json( email_address: User.first.email, - status: 'subscribed', + status: "subscribed", merge_fields: { NP_ID: User.first.roles.first.host.id, NP_SUPP: 1, @@ -77,22 +75,22 @@ } end - describe 'ignores deleted supporters' do - subject(:json) do + describe "ignores deleted supporters" do + subject(:json) do view.lookup_context.prefixes = view.lookup_context.prefixes.drop(1) user = create(:user_as_nonprofit_associate, :with_first_name) nonprofit = user.roles.first.host - supp = create(:supporter, nonprofit: nonprofit, deleted: true) + create(:supporter, nonprofit: nonprofit, deleted: true) assign(:user, user) assign(:nonprofit, user.roles.first.host) render rendered - end - + end + it { is_expected.to include_json( email_address: User.first.email, - status: 'subscribed', + status: "subscribed", merge_fields: { NP_ID: User.first.roles.first.host.id, NP_SUPP: 0, @@ -101,7 +99,5 @@ ) } end - end - -end - + end +end