From a4efd3d44cea8358fa02ccd3c4c6e2485e1c0083 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 16 Mar 2016 11:35:31 +0000 Subject: [PATCH 01/11] Adding configurable Shop Trial Length in business model --- .../admin/business_model_configuration_controller.rb | 3 ++- app/helpers/enterprises_helper.rb | 6 +++--- app/models/enterprise.rb | 3 +-- app/models/spree/app_configuration_decorator.rb | 1 + .../admin/business_model_configuration/edit.html.haml | 6 ++++++ .../business_model_configuration_validator.rb | 3 ++- .../business_model_configuration_controller_spec.rb | 9 +++++++-- 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/app/controllers/admin/business_model_configuration_controller.rb b/app/controllers/admin/business_model_configuration_controller.rb index 312a2e3208..38506e8368 100644 --- a/app/controllers/admin/business_model_configuration_controller.rb +++ b/app/controllers/admin/business_model_configuration_controller.rb @@ -18,8 +18,9 @@ class Admin::BusinessModelConfigurationController < Spree::Admin::BaseController def load_settings @settings = OpenFoodNetwork::BusinessModelConfigurationValidator.new(params[:settings] || { + shop_trial_length_days: Spree::Config[:shop_trial_length_days], account_invoices_monthly_fixed: Spree::Config[:account_invoices_monthly_fixed], - account_invoices_monthly_rate: Spree::Config[:account_invoices_monthly_rate], + account_invoiceaccount_invoices_monthly_rates_monthly_rate: Spree::Config[:account_invoices_monthly_rate], account_invoices_monthly_cap: Spree::Config[:account_invoices_monthly_cap], account_invoices_tax_rate: Spree::Config[:account_invoices_tax_rate] }) diff --git a/app/helpers/enterprises_helper.rb b/app/helpers/enterprises_helper.rb index 85d1167ab7..9f6810f34f 100644 --- a/app/helpers/enterprises_helper.rb +++ b/app/helpers/enterprises_helper.rb @@ -48,17 +48,17 @@ module EnterprisesHelper def shop_trial_in_progress?(enterprise) !!enterprise.shop_trial_start_date && - (enterprise.shop_trial_start_date + Enterprise::SHOP_TRIAL_LENGTH.days > Time.zone.now) && + (enterprise.shop_trial_start_date + Spree::Config[:shop_trial_length_days].days > Time.zone.now) && %w(own any).include?(enterprise.sells) end def shop_trial_expired?(enterprise) !!enterprise.shop_trial_start_date && - (enterprise.shop_trial_start_date + Enterprise::SHOP_TRIAL_LENGTH.days <= Time.zone.now) && + (enterprise.shop_trial_start_date + Spree::Config[:shop_trial_length_days].days <= Time.zone.now) && %w(own any).include?(enterprise.sells) end def remaining_trial_days(enterprise) - distance_of_time_in_words(Time.zone.now, enterprise.shop_trial_start_date + Enterprise::SHOP_TRIAL_LENGTH.days) + distance_of_time_in_words(Time.zone.now, enterprise.shop_trial_start_date + Spree::Config[:shop_trial_length_days].days) end end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 34a5d22f5b..58f47c5ed1 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -1,6 +1,5 @@ class Enterprise < ActiveRecord::Base SELLS = %w(unspecified none own any) - SHOP_TRIAL_LENGTH = 30 ENTERPRISE_SEARCH_RADIUS = 100 preference :shopfront_message, :text, default: "" @@ -332,7 +331,7 @@ class Enterprise < ActiveRecord::Base end def shop_trial_expiry - shop_trial_start_date.andand + Enterprise::SHOP_TRIAL_LENGTH.days + shop_trial_start_date.andand + Spree::Config[:shop_trial_length_days].days end def can_invoice? diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index fc7a8171cc..235aa3e2f1 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -20,4 +20,5 @@ Spree::AppConfiguration.class_eval do preference :account_invoices_monthly_rate, :decimal, default: 0 preference :account_invoices_monthly_cap, :decimal, default: 0 preference :account_invoices_tax_rate, :decimal, default: 0 + preference :shop_trial_length_days, :integer, default: 30 end diff --git a/app/views/admin/business_model_configuration/edit.html.haml b/app/views/admin/business_model_configuration/edit.html.haml index 89345178f9..91c562c81b 100644 --- a/app/views/admin/business_model_configuration/edit.html.haml +++ b/app/views/admin/business_model_configuration/edit.html.haml @@ -17,6 +17,12 @@ Adjust the amount that enterprises will be billed each month for use of the OFN. %br = form_for @settings, as: :settings, url: main_app.admin_business_model_configuration_path, :method => :put do |f| + .row + .three.columns.alpha + = f.label :shop_trial_length_days, t(:shop_trial_length) + %span.icon-question-sign{'ofn-with-tip' => "The length of time (in days) that enterprises who are set up as shops can run as a trial period."} + .two.columns.omega + = f.number_field :shop_trial_length_days, min: 0.0, step: 1.0, class: "fullwidth", 'watch-value-as' => 'fixed' .row .three.columns.alpha = f.label :account_invoices_monthly_fixed, t(:fixed_monthly_charge) diff --git a/lib/open_food_network/business_model_configuration_validator.rb b/lib/open_food_network/business_model_configuration_validator.rb index d83d94ffc1..0d6b4d9f83 100644 --- a/lib/open_food_network/business_model_configuration_validator.rb +++ b/lib/open_food_network/business_model_configuration_validator.rb @@ -5,8 +5,9 @@ module OpenFoodNetwork class BusinessModelConfigurationValidator include ActiveModel::Validations - attr_accessor :account_invoices_monthly_fixed, :account_invoices_monthly_rate, :account_invoices_monthly_cap, :account_invoices_tax_rate + attr_accessor :shop_trial_length_days, :account_invoices_monthly_fixed, :account_invoices_monthly_rate, :account_invoices_monthly_cap, :account_invoices_tax_rate + validates :shop_trial_length_days, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :account_invoices_monthly_fixed, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :account_invoices_monthly_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } validates :account_invoices_monthly_cap, presence: true, numericality: { greater_than_or_equal_to: 0 } diff --git a/spec/controllers/admin/business_model_configuration_controller_spec.rb b/spec/controllers/admin/business_model_configuration_controller_spec.rb index b0ae86d4ac..9c970c33f9 100644 --- a/spec/controllers/admin/business_model_configuration_controller_spec.rb +++ b/spec/controllers/admin/business_model_configuration_controller_spec.rb @@ -9,7 +9,8 @@ describe Admin::BusinessModelConfigurationController, type: :controller do account_invoices_monthly_fixed: 5, account_invoices_monthly_rate: 0.02, account_invoices_monthly_cap: 50, - account_invoices_tax_rate: 0.1 + account_invoices_tax_rate: 0.1, + shop_trial_length_days: 30 }) end @@ -53,16 +54,18 @@ describe Admin::BusinessModelConfigurationController, type: :controller do params[:settings][:account_invoices_monthly_rate] = '2' params[:settings][:account_invoices_monthly_cap] = '-1' params[:settings][:account_invoices_tax_rate] = '4' + params[:settings][:shop_trial_length_days] = '-30' spree_get :update, params end it "does not allow them to be set" do expect(response).to render_template :edit - expect(assigns(:settings).errors.count).to be 5 + expect(assigns(:settings).errors.count).to be 6 expect(Spree::Config.account_invoices_monthly_fixed).to eq 5 expect(Spree::Config.account_invoices_monthly_rate).to eq 0.02 expect(Spree::Config.account_invoices_monthly_cap).to eq 50 expect(Spree::Config.account_invoices_tax_rate).to eq 0.1 + expect(Spree::Config.shop_trial_length_days).to eq 30 end end @@ -72,6 +75,7 @@ describe Admin::BusinessModelConfigurationController, type: :controller do params[:settings][:account_invoices_monthly_rate] = '0.05' params[:settings][:account_invoices_monthly_cap] = '30' params[:settings][:account_invoices_tax_rate] = '0.15' + params[:settings][:shop_trial_length_days] = '20' end it "sets global config to the specified values" do @@ -81,6 +85,7 @@ describe Admin::BusinessModelConfigurationController, type: :controller do expect(Spree::Config.account_invoices_monthly_rate).to eq 0.05 expect(Spree::Config.account_invoices_monthly_cap).to eq 30 expect(Spree::Config.account_invoices_tax_rate).to eq 0.15 + expect(Spree::Config.shop_trial_length_days).to eq 20 end end end From d9d5d9cda5679b887ea130548e158a74aae7d3e2 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 16 Mar 2016 11:38:00 +0000 Subject: [PATCH 02/11] Fixing wild typo --- .../admin/business_model_configuration_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/business_model_configuration_controller.rb b/app/controllers/admin/business_model_configuration_controller.rb index 38506e8368..967238b347 100644 --- a/app/controllers/admin/business_model_configuration_controller.rb +++ b/app/controllers/admin/business_model_configuration_controller.rb @@ -20,7 +20,7 @@ class Admin::BusinessModelConfigurationController < Spree::Admin::BaseController @settings = OpenFoodNetwork::BusinessModelConfigurationValidator.new(params[:settings] || { shop_trial_length_days: Spree::Config[:shop_trial_length_days], account_invoices_monthly_fixed: Spree::Config[:account_invoices_monthly_fixed], - account_invoiceaccount_invoices_monthly_rates_monthly_rate: Spree::Config[:account_invoices_monthly_rate], + account_invoices_monthly_rate: Spree::Config[:account_invoices_monthly_rate], account_invoices_monthly_cap: Spree::Config[:account_invoices_monthly_cap], account_invoices_tax_rate: Spree::Config[:account_invoices_tax_rate] }) From ba49a5a783ac432db80394e84b1b4d3242f6e08a Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 16 Mar 2016 12:35:45 +0000 Subject: [PATCH 03/11] Adding translations for shop front trials --- app/views/spree/admin/shared/_trial_progress_bar.html.haml | 4 ++-- config/locales/en-GB.yml | 4 ++++ config/locales/en.yml | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/shared/_trial_progress_bar.html.haml b/app/views/spree/admin/shared/_trial_progress_bar.html.haml index abffdbd6ad..4c76e40705 100644 --- a/app/views/spree/admin/shared/_trial_progress_bar.html.haml +++ b/app/views/spree/admin/shared/_trial_progress_bar.html.haml @@ -1,7 +1,7 @@ - if enterprise -if shop_trial_in_progress?(enterprise) #trial_progress_bar - = "Your shopfront trial expires in #{remaining_trial_days(enterprise)}." + = "#{t(:shop_trial_expires_in)} #{remaining_trial_days(enterprise)}." -elsif shop_trial_expired?(enterprise) #trial_progress_bar - = "Good news! We have decided to extend shopfront trials until further notice (probably around March 2015)." \ No newline at end of file + = t(:shop_trial_expired_notice) diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 7301ef4f2c..cf8e7e78dc 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -635,3 +635,7 @@ Please follow the instructions there to make your enterprise visible on the Open price_graph: "Price graph" included_tax: "Included tax" remove_tax: "Remove tax" + shop_trial_length: "Shop Trial Length (Days)" + shop_trial_length: "Shop Trial Length (Days)" + shop_trial_expires_in: "Your shopfront trial expires in" + shop_trial_expired_notice: "Open Food Network UK is currently free while we prepare for our soft launch in April, 2016." diff --git a/config/locales/en.yml b/config/locales/en.yml index a5c5ba7903..86278e8f2c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -677,3 +677,6 @@ Please follow the instructions there to make your enterprise visible on the Open price_graph: "Price graph" included_tax: "Included tax" remove_tax: "Remove tax" + shop_trial_length: "Shop Trial Length (Days)" + shop_trial_expires_in: "Your shopfront trial expires in" + shop_trial_expired_notice: "Good news! We have decided to extend shopfront trials until further notice (probably around March 2015)." From b43e770420ad6c987b4fe84fc55220aff754cd34 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 16 Mar 2016 14:17:43 +0000 Subject: [PATCH 04/11] Removing incorrect angular watch --- app/views/admin/business_model_configuration/edit.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/business_model_configuration/edit.html.haml b/app/views/admin/business_model_configuration/edit.html.haml index 91c562c81b..4794c536b4 100644 --- a/app/views/admin/business_model_configuration/edit.html.haml +++ b/app/views/admin/business_model_configuration/edit.html.haml @@ -22,7 +22,7 @@ = f.label :shop_trial_length_days, t(:shop_trial_length) %span.icon-question-sign{'ofn-with-tip' => "The length of time (in days) that enterprises who are set up as shops can run as a trial period."} .two.columns.omega - = f.number_field :shop_trial_length_days, min: 0.0, step: 1.0, class: "fullwidth", 'watch-value-as' => 'fixed' + = f.number_field :shop_trial_length_days, min: 0.0, step: 1.0, class: "fullwidth" .row .three.columns.alpha = f.label :account_invoices_monthly_fixed, t(:fixed_monthly_charge) From bfaefa4dc941f2465dfbb4a092ef2b132ded53bf Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 17 Mar 2016 11:15:06 +0000 Subject: [PATCH 05/11] Updating Bill Calculator to include a minimum billable turnover. Shopfronts are not charged if their tunrover is under the minimum billable. --- lib/open_food_network/bill_calculator.rb | 4 +- spec/models/billable_period_spec.rb | 395 +++++++++++++++++++---- 2 files changed, 339 insertions(+), 60 deletions(-) diff --git a/lib/open_food_network/bill_calculator.rb b/lib/open_food_network/bill_calculator.rb index 84457d6530..d5302c0996 100644 --- a/lib/open_food_network/bill_calculator.rb +++ b/lib/open_food_network/bill_calculator.rb @@ -1,6 +1,6 @@ module OpenFoodNetwork class BillCalculator - attr_accessor :turnover, :fixed, :rate, :cap, :tax_rate + attr_accessor :turnover, :fixed, :rate, :cap, :tax_rate, :min_bill_to def initialize(opts={}) @turnover = opts[:turnover] || 0 @@ -8,11 +8,13 @@ module OpenFoodNetwork @rate = opts[:rate] || Spree::Config[:account_invoices_monthly_rate] @cap = opts[:cap] || Spree::Config[:account_invoices_monthly_cap] @tax_rate = opts[:tax_rate] || Spree::Config[:account_invoices_tax_rate] + @min_bill_to = opts[:min_bill_to] || Spree::Config[:minimum_billable_turnover] end def bill bill = fixed + (turnover * rate) bill = cap > 0 ? [bill, cap].min : bill + bill = turnover > min_bill_to ? bill : 0 bill * (1 + tax_rate) end end diff --git a/spec/models/billable_period_spec.rb b/spec/models/billable_period_spec.rb index 3037ebc6bc..b2a1b4470e 100644 --- a/spec/models/billable_period_spec.rb +++ b/spec/models/billable_period_spec.rb @@ -34,94 +34,371 @@ describe BillablePeriod, type: :model do context "when no tax is charged" do before { Spree::Config.set(:account_invoices_tax_rate, 0) } - context "when a fixed cost is included" do - before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + context "when no minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } - context "when a percentage of turnover is included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } - context "when the bill is capped" do - context "at a level higher than the fixed charge plus the product of the rate and turnover" do - before { Spree::Config.set(:account_invoices_monthly_cap, 65) } - it { expect(subject.bill).to eq 60 } + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 65) } + it { expect(subject.bill).to eq 60 } + end + + context "at a level lower than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 55) } + it { expect(subject.bill).to eq 55 } + end end - context "at a level lower than the fixed charge plus the product of the rate and turnover" do - before { Spree::Config.set(:account_invoices_monthly_cap, 55) } - it { expect(subject.bill).to eq 55 } + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 60 } end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 60 } + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 15) } + it { expect(subject.bill).to eq 10 } + end + + context "at a level lower than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 5) } + it { expect(subject.bill).to eq 5 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 10 } + end end end - context "when a percentage of turnover is not included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } - context "when the bill is capped" do - context "at a level higher than the fixed charge" do - before { Spree::Config.set(:account_invoices_monthly_cap, 15) } - it { expect(subject.bill).to eq 10 } + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 55) } + it { expect(subject.bill).to eq 50 } + end + + context "at a level lower than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 45) } + it { expect(subject.bill).to eq 45 } + end end - context "at a level lower than the fixed charge" do - before { Spree::Config.set(:account_invoices_monthly_cap, 5) } - it { expect(subject.bill).to eq 5 } + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 50 } end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 10 } + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(subject.bill).to eq 0 } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end end end end - context "when a fixed cost is not included" do - before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + context "when turnover is above minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, 99) } - context "when a percentage of turnover is included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } - context "when the bill is capped" do - context "at a level higher than the product of the rate and turnover" do - before { Spree::Config.set(:account_invoices_monthly_cap, 55) } - it { expect(subject.bill).to eq 50 } + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 65) } + it { expect(subject.bill).to eq 60 } + end + + context "at a level lower than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 55) } + it { expect(subject.bill).to eq 55 } + end end - context "at a level lower than the product of the rate and turnover" do - before { Spree::Config.set(:account_invoices_monthly_cap, 45) } - it { expect(subject.bill).to eq 45 } + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 60 } end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 50 } + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 15) } + it { expect(subject.bill).to eq 10 } + end + + context "at a level lower than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 5) } + it { expect(subject.bill).to eq 5 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 10 } + end end end - context "when a percentage of turnover is not included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(subject.bill).to eq 0 } + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 55) } + it { expect(subject.bill).to eq 50 } + end + + context "at a level lower than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 45) } + it { expect(subject.bill).to eq 45 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 50 } + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 0 } + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(subject.bill).to eq 0 } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end + end + end + end + + context "when turnover is below minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, 101) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 65) } + it { expect(subject.bill).to eq 0 } + end + + context "at a level lower than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 55) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 15) } + it { expect(subject.bill).to eq 0 } + end + + context "at a level lower than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 5) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end + end + end + + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 55) } + it { expect(subject.bill).to eq 0 } + end + + context "at a level lower than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 45) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(subject.bill).to eq 0 } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end + end + end + end + + context "when tax is charged" do + before { Spree::Config.set(:account_invoices_tax_rate, 0.1) } + + context "when turnover is above minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, 99) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 61) } + it { expect(subject.bill).to eq 66 } + end + + context "at a level lower than the fixed charge plus the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 59) } + it { + expect(subject.bill.to_f).to eq 64.9 + } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 66 } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + context "at a level higher than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 11) } + it { expect(subject.bill).to eq 11 } + end + + context "at a level lower than the fixed charge" do + before { Spree::Config.set(:account_invoices_monthly_cap, 9) } + it { expect(subject.bill.to_f).to eq 9.9 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 11 } + end + end + end + + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) } + + context "when the bill is capped" do + context "at a level higher than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 51) } + it { expect(subject.bill).to eq 55 } + end + + context "at a level lower than the product of the rate and turnover" do + before { Spree::Config.set(:account_invoices_monthly_cap, 49) } + it { expect(subject.bill.to_f).to eq 53.9 } + end + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 55 } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(subject.bill).to eq 0 } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(subject.bill).to eq 0 } + end + end end end end end - context "when tax is charged" do - before { Spree::Config.set(:account_invoices_tax_rate, 0.1) } + context "when turnover is below minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, 101) } context "when a fixed cost is included" do before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } @@ -132,20 +409,20 @@ describe BillablePeriod, type: :model do context "when the bill is capped" do context "at a level higher than the fixed charge plus the product of the rate and turnover" do before { Spree::Config.set(:account_invoices_monthly_cap, 61) } - it { expect(subject.bill).to eq 66 } + it { expect(subject.bill).to eq 0 } end context "at a level lower than the fixed charge plus the product of the rate and turnover" do before { Spree::Config.set(:account_invoices_monthly_cap, 59) } it { - expect(subject.bill.to_f).to eq 64.9 + expect(subject.bill.to_f).to eq 0 } end end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 66 } + it { expect(subject.bill).to eq 0 } end end @@ -155,18 +432,18 @@ describe BillablePeriod, type: :model do context "when the bill is capped" do context "at a level higher than the fixed charge" do before { Spree::Config.set(:account_invoices_monthly_cap, 11) } - it { expect(subject.bill).to eq 11 } + it { expect(subject.bill).to eq 0 } end context "at a level lower than the fixed charge" do before { Spree::Config.set(:account_invoices_monthly_cap, 9) } - it { expect(subject.bill.to_f).to eq 9.9 } + it { expect(subject.bill.to_f).to eq 0 } end end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 11 } + it { expect(subject.bill).to eq 0 } end end end @@ -180,18 +457,18 @@ describe BillablePeriod, type: :model do context "when the bill is capped" do context "at a level higher than the product of the rate and turnover" do before { Spree::Config.set(:account_invoices_monthly_cap, 51) } - it { expect(subject.bill).to eq 55 } + it { expect(subject.bill).to eq 0 } end context "at a level lower than the product of the rate and turnover" do before { Spree::Config.set(:account_invoices_monthly_cap, 49) } - it { expect(subject.bill.to_f).to eq 53.9 } + it { expect(subject.bill.to_f).to eq 0 } end end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(subject.bill).to eq 55 } + it { expect(subject.bill).to eq 0 } end end From 430c6c0642bd34b82aeabcc3e269ec4a54958948 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 17 Mar 2016 12:22:27 +0000 Subject: [PATCH 06/11] Adding preference def for minimum_billable_turnover --- app/models/spree/app_configuration_decorator.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index 235aa3e2f1..7959b63944 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -21,4 +21,5 @@ Spree::AppConfiguration.class_eval do preference :account_invoices_monthly_cap, :decimal, default: 0 preference :account_invoices_tax_rate, :decimal, default: 0 preference :shop_trial_length_days, :integer, default: 30 + preference :minimum_billable_turnover, :integer, default: -1 end From da10b5decf97600d0a29b71cbd7d2f003c4bd681 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 17 Mar 2016 12:24:34 +0000 Subject: [PATCH 07/11] Updating spec with minimum_billable_turnover preference --- spec/jobs/update_account_invoices_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/jobs/update_account_invoices_spec.rb b/spec/jobs/update_account_invoices_spec.rb index 87d601b60a..60b26248cc 100644 --- a/spec/jobs/update_account_invoices_spec.rb +++ b/spec/jobs/update_account_invoices_spec.rb @@ -12,6 +12,7 @@ describe UpdateAccountInvoices do Spree::Config.set(:account_invoices_monthly_fixed, 5) Spree::Config.set(:account_invoices_monthly_rate, 0.02) Spree::Config.set(:account_invoices_monthly_cap, 50) + Spree::Config.set(:minimum_billable_turnover, -1) end describe "units specs" do From 2d97bc49bdac51ec1030df66e18764578ee074bc Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 17 Mar 2016 12:36:38 +0000 Subject: [PATCH 08/11] Updating specs to explore the cases around zero turnover with fixed rate and minimum billable turnover --- spec/models/billable_period_spec.rb | 69 ++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/spec/models/billable_period_spec.rb b/spec/models/billable_period_spec.rb index b2a1b4470e..e79c0a2cd2 100644 --- a/spec/models/billable_period_spec.rb +++ b/spec/models/billable_period_spec.rb @@ -27,6 +27,73 @@ describe BillablePeriod, type: :model do end end + describe "calculating monthly bills for enterprises with no turnover" do + let!(:subject) { create(:billable_period, turnover: 0) } + + context "when no tax is charged" do + before { Spree::Config.set(:account_invoices_tax_rate, 0) } + + context "when no minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, -1) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + it { expect(subject.bill).to eq 10 } + end + + context "when no fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when minimum billable turnover exists" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + it { expect(subject.bill).to eq 0 } + end + + context "when no fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + it { expect(subject.bill).to eq 0 } + end + end + end + + context "when tax is charged" do + before { Spree::Config.set(:account_invoices_tax_rate, 0.1) } + + context "when no minimum billable turnover" do + before { Spree::Config.set(:minimum_billable_turnover, -1) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + it { expect(subject.bill).to eq 11 } + end + + context "when no fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + it { expect(subject.bill).to eq 0 } + end + end + + context "when minimum billable turnover exists" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + it { expect(subject.bill).to eq 0 } + end + + context "when no fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + it { expect(subject.bill).to eq 0 } + end + end + end + end describe "calculating monthly bills for enterprises" do let!(:subject) { create(:billable_period, turnover: 100) } @@ -35,7 +102,7 @@ describe BillablePeriod, type: :model do before { Spree::Config.set(:account_invoices_tax_rate, 0) } context "when no minimum billable turnover" do - before { Spree::Config.set(:minimum_billable_turnover, 0) } + before { Spree::Config.set(:minimum_billable_turnover, -1) } context "when a fixed cost is included" do before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } From 096962b778c32a4089ba8c21e7778ff4423534d7 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 17 Mar 2016 12:54:03 +0000 Subject: [PATCH 09/11] Adding super admin configuration for the minimum billable turnover functionality --- .../business_model_configuration_controller.js.coffee | 6 +++++- .../admin/business_model_configuration_controller.rb | 4 +++- .../admin/business_model_configuration/edit.html.haml | 10 +++++++++- .../business_model_configuration_validator.rb | 3 ++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/admin/business_model_configuration/controllers/business_model_configuration_controller.js.coffee b/app/assets/javascripts/admin/business_model_configuration/controllers/business_model_configuration_controller.js.coffee index ca757c673d..8229def620 100644 --- a/app/assets/javascripts/admin/business_model_configuration/controllers/business_model_configuration_controller.js.coffee +++ b/app/assets/javascripts/admin/business_model_configuration/controllers/business_model_configuration_controller.js.coffee @@ -9,6 +9,10 @@ angular.module("admin.businessModelConfiguration").controller "BusinessModelConf return $scope.bill() if !$scope.cap? || Number($scope.cap) == 0 Math.min($scope.bill(), Number($scope.cap)) + $scope.finalBill = -> + return 0 if Number($scope.turnover) <= Number($scope.min_bill_to) + $scope.cappedBill() + $scope.capReached = -> return "No" if !$scope.cap? || Number($scope.cap) == 0 if $scope.bill() >= Number($scope.cap) then "Yes" else "No" @@ -18,4 +22,4 @@ angular.module("admin.businessModelConfiguration").controller "BusinessModelConf ($scope.cappedBill() * Number($scope.taxRate)) $scope.total = -> - $scope.cappedBill() + $scope.includedTax() + $scope.finalBill() + $scope.includedTax() diff --git a/app/controllers/admin/business_model_configuration_controller.rb b/app/controllers/admin/business_model_configuration_controller.rb index 967238b347..b3c3c67ab8 100644 --- a/app/controllers/admin/business_model_configuration_controller.rb +++ b/app/controllers/admin/business_model_configuration_controller.rb @@ -22,7 +22,9 @@ class Admin::BusinessModelConfigurationController < Spree::Admin::BaseController account_invoices_monthly_fixed: Spree::Config[:account_invoices_monthly_fixed], account_invoices_monthly_rate: Spree::Config[:account_invoices_monthly_rate], account_invoices_monthly_cap: Spree::Config[:account_invoices_monthly_cap], - account_invoices_tax_rate: Spree::Config[:account_invoices_tax_rate] + account_invoices_tax_rate: Spree::Config[:account_invoices_tax_rate], + minimum_billable_turnover: Spree::Config[:minimum_billable_turnover] + }) end diff --git a/app/views/admin/business_model_configuration/edit.html.haml b/app/views/admin/business_model_configuration/edit.html.haml index 4794c536b4..8a5c368444 100644 --- a/app/views/admin/business_model_configuration/edit.html.haml +++ b/app/views/admin/business_model_configuration/edit.html.haml @@ -26,7 +26,7 @@ .row .three.columns.alpha = f.label :account_invoices_monthly_fixed, t(:fixed_monthly_charge) - %span.icon-question-sign{'ofn-with-tip' => "A fixed monthly charge for ALL enterprises who are set up as a shop, regardless of how much produce they sell."} + %span.icon-question-sign{'ofn-with-tip' => "A fixed monthly charge for all enterprises who are set up as a shop and have exceeded the minimum billable turnover (if set)."} .two.columns.omega .input-symbol.before %span= Spree::Money.currency_symbol @@ -51,6 +51,14 @@ %span.icon-question-sign{'ofn-with-tip' => "Tax rate that applies to the the monthly bill that enterprises are charged for using the system."} .two.columns.omega = f.number_field :account_invoices_tax_rate, min: 0.0, max: 1.0, step: 0.01, class: "fullwidth", 'watch-value-as' => 'taxRate' + .row + .three.columns.alpha + = f.label :minimum_billable_turnover, t(:minimum_monthly_billable_turnover) + %span.icon-question-sign{'ofn-with-tip' => "Minimum monthly turnover before a shopfront will be charged for using OFN. Enterprises turning over less than this amount in a month will not be charged, either as a percentage or fixed rate. When set to -1 enterprises with no turnover will be charge the fixed rate as specified."} + .two.columns.omega + .input-symbol.before + %span= Spree::Money.currency_symbol + = f.number_field :minimum_billable_turnover, min: -1.0, class: "fullwidth", 'watch-value-as' => 'min_bill_to' .row .five.columns.alpha.omega.form-buttons{"data-hook" => "buttons"} diff --git a/lib/open_food_network/business_model_configuration_validator.rb b/lib/open_food_network/business_model_configuration_validator.rb index 0d6b4d9f83..1e1c077808 100644 --- a/lib/open_food_network/business_model_configuration_validator.rb +++ b/lib/open_food_network/business_model_configuration_validator.rb @@ -5,13 +5,14 @@ module OpenFoodNetwork class BusinessModelConfigurationValidator include ActiveModel::Validations - attr_accessor :shop_trial_length_days, :account_invoices_monthly_fixed, :account_invoices_monthly_rate, :account_invoices_monthly_cap, :account_invoices_tax_rate + attr_accessor :shop_trial_length_days, :account_invoices_monthly_fixed, :account_invoices_monthly_rate, :account_invoices_monthly_cap, :account_invoices_tax_rate, :minimum_billable_turnover validates :shop_trial_length_days, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :account_invoices_monthly_fixed, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :account_invoices_monthly_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } validates :account_invoices_monthly_cap, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :account_invoices_tax_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } + validates :minimum_billable_turnover, presence: true, numericality: { greater_than_or_equal_to: -1 } def initialize(attr, button=nil) attr.each { |k,v| instance_variable_set("@#{k}", v) } From 56a6593dd6b66783bf28adb47008802f511de641 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 17 Mar 2016 13:40:25 +0000 Subject: [PATCH 10/11] Missing Specs --- .../business_model_configuration_controller_spec.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/controllers/admin/business_model_configuration_controller_spec.rb b/spec/controllers/admin/business_model_configuration_controller_spec.rb index 9c970c33f9..4bbf831bb6 100644 --- a/spec/controllers/admin/business_model_configuration_controller_spec.rb +++ b/spec/controllers/admin/business_model_configuration_controller_spec.rb @@ -10,7 +10,8 @@ describe Admin::BusinessModelConfigurationController, type: :controller do account_invoices_monthly_rate: 0.02, account_invoices_monthly_cap: 50, account_invoices_tax_rate: 0.1, - shop_trial_length_days: 30 + shop_trial_length_days: 30, + minimum_billable_turnover: -1 }) end @@ -55,17 +56,19 @@ describe Admin::BusinessModelConfigurationController, type: :controller do params[:settings][:account_invoices_monthly_cap] = '-1' params[:settings][:account_invoices_tax_rate] = '4' params[:settings][:shop_trial_length_days] = '-30' + params[:settings][:minimum_billable_turnover] = '-2' spree_get :update, params end it "does not allow them to be set" do expect(response).to render_template :edit - expect(assigns(:settings).errors.count).to be 6 + expect(assigns(:settings).errors.count).to be 7 expect(Spree::Config.account_invoices_monthly_fixed).to eq 5 expect(Spree::Config.account_invoices_monthly_rate).to eq 0.02 expect(Spree::Config.account_invoices_monthly_cap).to eq 50 expect(Spree::Config.account_invoices_tax_rate).to eq 0.1 expect(Spree::Config.shop_trial_length_days).to eq 30 + expect(Spree::Config.minimum_billable_turnover).to eq -1 end end @@ -76,6 +79,7 @@ describe Admin::BusinessModelConfigurationController, type: :controller do params[:settings][:account_invoices_monthly_cap] = '30' params[:settings][:account_invoices_tax_rate] = '0.15' params[:settings][:shop_trial_length_days] = '20' + params[:settings][:minimum_billable_turnover] = '0' end it "sets global config to the specified values" do @@ -86,6 +90,7 @@ describe Admin::BusinessModelConfigurationController, type: :controller do expect(Spree::Config.account_invoices_monthly_cap).to eq 30 expect(Spree::Config.account_invoices_tax_rate).to eq 0.15 expect(Spree::Config.shop_trial_length_days).to eq 20 + expect(Spree::Config.minimum_billable_turnover).to eq 0 end end end From 7b75fab7a1a60edad156ab131378c87416b6ab3a Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Thu, 24 Mar 2016 16:57:56 +0000 Subject: [PATCH 11/11] Code tidying and currency symbol internationalisation --- .../edit.html.haml | 6 ++++-- lib/open_food_network/bill_calculator.rb | 21 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/app/views/admin/business_model_configuration/edit.html.haml b/app/views/admin/business_model_configuration/edit.html.haml index 8a5c368444..a38e22eb17 100644 --- a/app/views/admin/business_model_configuration/edit.html.haml +++ b/app/views/admin/business_model_configuration/edit.html.haml @@ -92,10 +92,12 @@ = label_tag :included_tax, t(:included_tax) %span.icon-question-sign{'ofn-with-tip' => "The total tax included in the example monthly bill, given the settings and the turnover provided."} .two.columns.omega - %input.fullwidth{ id: 'included_tax', type: "text", readonly: true, ng: { value: 'includedTax() | currency' } } + %span= Spree::Money.currency_symbol + %input.fullwidth{ id: 'included_tax', type: "text", readonly: true, ng: { value: 'includedTax()' } } .row .three.columns.alpha = label_tag :total_incl_tax, t(:total_monthly_bill_incl_tax) %span.icon-question-sign{'ofn-with-tip' => "The example total monthly bill with tax included, given the settings and the turnover provided."} .two.columns.omega - %input.fullwidth{ id: 'total_incl_tax', type: "text", readonly: true, ng: { value: 'total() | currency' } } + %span= Spree::Money.currency_symbol + %input.fullwidth{ id: 'total_incl_tax', type: "text", readonly: true, ng: { value: 'total()' } } diff --git a/lib/open_food_network/bill_calculator.rb b/lib/open_food_network/bill_calculator.rb index d5302c0996..207a799bda 100644 --- a/lib/open_food_network/bill_calculator.rb +++ b/lib/open_food_network/bill_calculator.rb @@ -1,21 +1,24 @@ -module OpenFoodNetwork + module OpenFoodNetwork class BillCalculator attr_accessor :turnover, :fixed, :rate, :cap, :tax_rate, :min_bill_to def initialize(opts={}) - @turnover = opts[:turnover] || 0 - @fixed = opts[:fixed] || Spree::Config[:account_invoices_monthly_fixed] - @rate = opts[:rate] || Spree::Config[:account_invoices_monthly_rate] - @cap = opts[:cap] || Spree::Config[:account_invoices_monthly_cap] - @tax_rate = opts[:tax_rate] || Spree::Config[:account_invoices_tax_rate] - @min_bill_to = opts[:min_bill_to] || Spree::Config[:minimum_billable_turnover] + defaults = { + fixed: :account_invoices_monthly_fixed + rate: :account_invoices_monthly_rate + cap: :account_invoices_monthly_cap + tax_rate: :account_invoices_tax_rate + min_bill_to: :minimum_billable_turnover + } + defaults.each do |key, config| + this[key] = opts[key] || Spree::Config[config] + end end def bill bill = fixed + (turnover * rate) - bill = cap > 0 ? [bill, cap].min : bill + bill = [bill, cap].min if cap > 0 bill = turnover > min_bill_to ? bill : 0 bill * (1 + tax_rate) end - end end