From 6e00833dbc66a090d620df392970dd2dd3799c3d Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 5 May 2015 14:05:35 -0700 Subject: [PATCH] RFC: order interface and actions --- core/app/models/spree/actions/action.rb | 18 ++++++++++ .../models/spree/actions/associate_user.rb | 29 +++++++++++++++ .../models/spree/actions/capture_payment.rb | 36 +++++++++++++++++++ core/app/models/spree/order.rb | 18 +++------- core/app/models/spree/order_interface.rb | 24 +++++++++++++ core/app/models/spree/payment.rb | 14 -------- core/app/models/spree/payment/processing.rb | 20 +++-------- core/spec/models/spree/payment_spec.rb | 5 +-- 8 files changed, 117 insertions(+), 47 deletions(-) create mode 100644 core/app/models/spree/actions/action.rb create mode 100644 core/app/models/spree/actions/associate_user.rb create mode 100644 core/app/models/spree/actions/capture_payment.rb create mode 100644 core/app/models/spree/order_interface.rb diff --git a/core/app/models/spree/actions/action.rb b/core/app/models/spree/actions/action.rb new file mode 100644 index 00000000000..9831e7c7f7f --- /dev/null +++ b/core/app/models/spree/actions/action.rb @@ -0,0 +1,18 @@ +module Spree + module Actions + class Action + def call + mutex do + perform + end + end + + private + + # FIXME: waiting on nested mutexes being supported + def mutex + yield + end + end + end +end diff --git a/core/app/models/spree/actions/associate_user.rb b/core/app/models/spree/actions/associate_user.rb new file mode 100644 index 00000000000..829fddc4724 --- /dev/null +++ b/core/app/models/spree/actions/associate_user.rb @@ -0,0 +1,29 @@ +module Spree + module Actions + class AssociateUser + attr_reader :order, :user, :override_email + + def initialize(order, user, override_email: true) + @order = order + @user = user + @override_email = override_email + end + + def perform + order.user = user + attrs_to_set = { user_id: user.try!(:id) } + attrs_to_set[:email] = user.try!(:email) if override_email + attrs_to_set[:created_by_id] = user.try!(:id) if order.created_by.blank? + + if order.persisted? + # immediately persist the changes we just made, but don't use save since we might have an invalid address associated + Spree::Order.unscoped.where(id: order.id).update_all(attrs_to_set) + end + + attrs_to_set[:ship_address_attributes] = user.ship_address.attributes.except('id', 'updated_at', 'created_at') if user.try!(:ship_address) + attrs_to_set[:bill_address_attributes] = user.bill_address.attributes.except('id', 'updated_at', 'created_at') if user.try!(:bill_address) + order.assign_attributes(attrs_to_set) + end + end + end +end diff --git a/core/app/models/spree/actions/capture_payment.rb b/core/app/models/spree/actions/capture_payment.rb new file mode 100644 index 00000000000..caf47f8c463 --- /dev/null +++ b/core/app/models/spree/actions/capture_payment.rb @@ -0,0 +1,36 @@ +module Spree + module Actions + class CapturePayment < Action + attr_reader :payment + + def initialize(payment, amount: nil) + @payment = payment + @amount = amount + end + + def amount + @amount ||= payment.money.money.cents + end + + def perform + return true if payment.completed? + payment.started_processing! + begin + #payment.check_environment + # Standard ActiveMerchant capture usage + response = payment.payment_method.capture( + amount, + payment.response_code, + payment.gateway_options + ) + money = ::Money.new(amount, payment.currency) + payment.capture_events.create!(amount: money.to_f) + payment.update_attributes(amount: payment.captured_amount) + payment.handle_response(response, :complete, :failure) + rescue ActiveMerchant::ConnectionError => e + + end + end + end + end +end diff --git a/core/app/models/spree/order.rb b/core/app/models/spree/order.rb index ad595f2ac0e..05b2d8557a2 100644 --- a/core/app/models/spree/order.rb +++ b/core/app/models/spree/order.rb @@ -246,21 +246,13 @@ def cancellations @cancellations ||= Spree::OrderCancellations.new(self) end + def interface + Spree::OrderInterface.new(self) + end + # Associates the specified user with the order. def associate_user!(user, override_email = true) - self.user = user - attrs_to_set = { user_id: user.try(:id) } - attrs_to_set[:email] = user.try(:email) if override_email - attrs_to_set[:created_by_id] = user.try(:id) if self.created_by.blank? - - if persisted? - # immediately persist the changes we just made, but don't use save since we might have an invalid address associated - self.class.unscoped.where(id: id).update_all(attrs_to_set) - end - - attrs_to_set[:ship_address_attributes] = user.ship_address.attributes.except('id', 'updated_at', 'created_at') if user.try(:ship_address) - attrs_to_set[:bill_address_attributes] = user.bill_address.attributes.except('id', 'updated_at', 'created_at') if user.try(:bill_address) - assign_attributes(attrs_to_set) + interface.associate_user(user, override_email: override_email) end def generate_order_number(options = {}) diff --git a/core/app/models/spree/order_interface.rb b/core/app/models/spree/order_interface.rb new file mode 100644 index 00000000000..4848714aba2 --- /dev/null +++ b/core/app/models/spree/order_interface.rb @@ -0,0 +1,24 @@ +module Spree + class OrderInterface + attr_reader :order + + def initialize(order) + @order = order + end + + delegate :add, :remove, :update_cart, to: :contents + + def associate_user(user, override_email: true) + Spree::Actions::AssociateUser.new(order, user, override_email: override_email).call + end + + def capture_payment(payment, amount: nil) + Spree::Actions::CapturePayment.new(payment, amount: amount).call + end + + private + def contents + Order::Contents.new(contents) + end + end +end diff --git a/core/app/models/spree/payment.rb b/core/app/models/spree/payment.rb index 9bc11a93658..5ac74ef0120 100644 --- a/core/app/models/spree/payment.rb +++ b/core/app/models/spree/payment.rb @@ -206,20 +206,6 @@ def invalidate_old_payments end end - def split_uncaptured_amount - if uncaptured_amount > 0 - order.payments.create! amount: uncaptured_amount, - avs_response: avs_response, - cvv_response_code: cvv_response_code, - cvv_response_message: cvv_response_message, - payment_method: payment_method, - response_code: response_code, - source: source, - state: 'pending' - update_attributes(amount: captured_amount) - end - end - def update_order if completed? || void? order.updater.update_payment_total diff --git a/core/app/models/spree/payment/processing.rb b/core/app/models/spree/payment/processing.rb index 70d4afd2352..508516e5910 100644 --- a/core/app/models/spree/payment/processing.rb +++ b/core/app/models/spree/payment/processing.rb @@ -22,22 +22,7 @@ def purchase! # Can be used to capture partial amounts of a payment, and will create # a new pending payment record for the remaining amount to capture later. def capture!(amount = nil) - return true if completed? - amount ||= money.money.cents - started_processing! - protect_from_connection_error do - check_environment - # Standard ActiveMerchant capture usage - response = payment_method.capture( - amount, - response_code, - gateway_options - ) - money = ::Money.new(amount, currency) - capture_events.create!(amount: money.to_f) - split_uncaptured_amount - handle_response(response, :complete, :failure) - end + order.interface.capture_payment(self, amount: amount) end def void_transaction! @@ -153,6 +138,9 @@ def handle_response(response, success_state, failure_state) end end + # FIXME + public :handle_response + def handle_void_response(response) record_response(response) diff --git a/core/spec/models/spree/payment_spec.rb b/core/spec/models/spree/payment_spec.rb index 70d0a1210c2..35ff4c9909b 100644 --- a/core/spec/models/spree/payment_spec.rb +++ b/core/spec/models/spree/payment_spec.rb @@ -341,17 +341,14 @@ expect(payment.payment_method).to receive(:capture).with(capture_amount, payment.response_code, anything).and_return(success_response) end - it "should make payment complete & create pending payment for remaining amount" do + it "should make payment complete and update amount" do expect(payment).to receive(:complete!) payment.capture!(capture_amount) order = payment.order payments = order.payments - expect(payments.size).to eq 2 - expect(payments.pending.first.amount).to eq 1 # Payment stays processing for spec because of receive(:complete!) stub. expect(payments.processing.first.amount).to eq(capture_amount / 100) - expect(payments.processing.first.source).to eq(payments.pending.first.source) end it "logs capture events" do