From f4cbd904001aab64066623e4c0664a75e3f24c2f Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 30 Nov 2016 12:48:34 +1100 Subject: [PATCH] Storing estimated prices for standing line items in the database --- .../admin/standing_orders_controller.rb | 5 +- app/forms/standing_order_form.rb | 27 +++++++++- .../admin/standing_line_item_serializer.rb | 4 +- ...d_price_estimate_to_standing_line_items.rb | 5 ++ db/schema.rb | 11 ++-- spec/forms/standing_order_form_spec.rb | 52 +++++++++++++++++++ 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20161130001339_add_price_estimate_to_standing_line_items.rb diff --git a/app/controllers/admin/standing_orders_controller.rb b/app/controllers/admin/standing_orders_controller.rb index ce5560d7e7..4e2d02dc55 100644 --- a/app/controllers/admin/standing_orders_controller.rb +++ b/app/controllers/admin/standing_orders_controller.rb @@ -9,7 +9,6 @@ module Admin respond_to :json def index - respond_to do |format| format.html do @payment_methods = Spree::PaymentMethod.managed_by(spree_current_user) @@ -25,7 +24,7 @@ module Admin end def create - form = StandingOrderForm.new(@standing_order, params[:standing_order]) + form = StandingOrderForm.new(@standing_order, params[:standing_order], fee_calculator) if form.save render_as_json @standing_order, fee_calculator: fee_calculator else @@ -34,7 +33,7 @@ module Admin end def update - form = StandingOrderForm.new(@standing_order, params[:standing_order]) + form = StandingOrderForm.new(@standing_order, params[:standing_order], fee_calculator) if form.save render_as_json @standing_order, ams_prefix: params[:ams_prefix], fee_calculator: fee_calculator else diff --git a/app/forms/standing_order_form.rb b/app/forms/standing_order_form.rb index b88c6fbe45..ddf39ca316 100644 --- a/app/forms/standing_order_form.rb +++ b/app/forms/standing_order_form.rb @@ -3,20 +3,22 @@ class StandingOrderForm include ActiveModel::Conversion include ActiveModel::Validations - attr_accessor :standing_order, :params + attr_accessor :standing_order, :params, :fee_calculator delegate :orders, :order_cycles, :bill_address, :ship_address, :standing_line_items, to: :standing_order delegate :shop, :shop_id, :customer, :customer_id, :begins_at, :ends_at, :standing_order_orders, to: :standing_order delegate :shipping_method, :shipping_method_id, :payment_method, :payment_method_id, to: :standing_order delegate :shipping_method_id_changed?, :shipping_method_id_was, :payment_method_id_changed?, :payment_method_id_was, to: :standing_order - def initialize(standing_order, params={}) + def initialize(standing_order, params={}, fee_calculator=nil) @standing_order = standing_order @params = params + @fee_calculator = fee_calculator end def save @standing_order.transaction do + validate_price_estimates @standing_order.assign_attributes(params) initialise_orders! @@ -129,4 +131,25 @@ class StandingOrderForm def line_items_from_future_and_undated_orders(variant_id) Spree::LineItem.where(order_id: future_and_undated_orders, variant_id: variant_id) end + + def validate_price_estimates + item_attributes = params[:standing_line_items_attributes] + return unless item_attributes.present? + if fee_calculator + item_attributes.each do |item_attrs| + if variant = Spree::Variant.find_by_id(item_attrs[:variant_id]) + item_attrs[:price_estimate] = price_estimate_for(variant) + else + item_attrs.delete(:price_estimate) + end + end + else + item_attributes.each { |item_attrs| item_attrs.delete(:price_estimate) } + end + end + + def price_estimate_for(variant) + fees = fee_calculator.indexed_fees_for(variant) + (variant.price + fees).to_d + end end diff --git a/app/serializers/api/admin/standing_line_item_serializer.rb b/app/serializers/api/admin/standing_line_item_serializer.rb index 7975bd5b93..e152c5fe44 100644 --- a/app/serializers/api/admin/standing_line_item_serializer.rb +++ b/app/serializers/api/admin/standing_line_item_serializer.rb @@ -6,7 +6,9 @@ class Api::Admin::StandingLineItemSerializer < ActiveModel::Serializer end def price_estimate - if options[:fee_calculator] + if object.price_estimate + object.price_estimate + elsif options[:fee_calculator] (object.variant.price + options[:fee_calculator].indexed_fees_for(object.variant)).to_f else "?" diff --git a/db/migrate/20161130001339_add_price_estimate_to_standing_line_items.rb b/db/migrate/20161130001339_add_price_estimate_to_standing_line_items.rb new file mode 100644 index 0000000000..967a24b838 --- /dev/null +++ b/db/migrate/20161130001339_add_price_estimate_to_standing_line_items.rb @@ -0,0 +1,5 @@ +class AddPriceEstimateToStandingLineItems < ActiveRecord::Migration + def change + add_column :standing_line_items, :price_estimate, :decimal, :precision => 8, :scale => 2 + end +end diff --git a/db/schema.rb b/db/schema.rb index 2abdbc1573..8f2b3f1d35 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1065,11 +1065,12 @@ ActiveRecord::Schema.define(:version => 20170921065259) do end create_table "standing_line_items", :force => true do |t| - t.integer "standing_order_id", :null => false - t.integer "variant_id", :null => false - t.integer "quantity", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.integer "standing_order_id", :null => false + t.integer "variant_id", :null => false + t.integer "quantity", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.decimal "price_estimate", :precision => 8, :scale => 2 end add_index "standing_line_items", ["standing_order_id"], :name => "index_standing_line_items_on_standing_order_id" diff --git a/spec/forms/standing_order_form_spec.rb b/spec/forms/standing_order_form_spec.rb index b0aa6446fd..61a3da8f0f 100644 --- a/spec/forms/standing_order_form_spec.rb +++ b/spec/forms/standing_order_form_spec.rb @@ -217,5 +217,57 @@ module OpenFoodNetwork expect(line_items.map(&:quantity)).to eq [4] end end + + describe "validating price_estimates on standing line items" do + let(:params) { { } } + let(:form) { StandingOrderForm.new(nil, params) } + + context "when line_item params are present" do + before { allow(form).to receive(:price_estimate_for) } + + it "does nothing" do + form.send(:validate_price_estimates) + expect(form.params[:standing_line_items_attributes]).to be nil + end + end + + context "when line_item params are present" do + before do + params[:standing_line_items_attributes] = [ { id: 1, price_estimate: 2.50 }, { id: 2, price_estimate: 3.50 }] + end + + context "when no fee calculator is present" do + before { allow(form).to receive(:price_estimate_for) } + + it "clears price estimates on all standing line item attributes" do + form.send(:validate_price_estimates) + attrs = form.params[:standing_line_items_attributes] + expect(attrs.first.keys).to_not include :price_estimate + expect(attrs.last.keys).to_not include :price_estimate + expect(form).to_not have_received(:price_estimate_for) + end + end + + context "when a fee calculator is present" do + let(:variant) { create(:variant) } + let(:fee_calculator) { double(:fee_calculator) } + + before do + allow(form).to receive(:fee_calculator) { fee_calculator } + allow(form).to receive(:price_estimate_for) { 5.30 } + params[:standing_line_items_attributes].first[:variant_id] = variant.id + end + + it "clears price estimates on standing line item attributes without variant ids" do + form.send(:validate_price_estimates) + attrs = form.params[:standing_line_items_attributes] + expect(attrs.first.keys).to include :price_estimate + expect(attrs.last.keys).to_not include :price_estimate + expect(attrs.first[:price_estimate]).to eq 5.30 + expect(form).to have_received(:price_estimate_for).with(variant) + end + end + end + end end end