Created
November 13, 2012 19:24
-
-
Save r00k/4067818 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 093625b9f1ac705d8821cbbc2f9449558c555c01 | |
Author: Ben Orenstein <[email protected]> | |
Date: Tue Nov 13 14:05:20 2012 -0500 | |
Extract an OrderRefunder | |
diff --git a/app/models/order.rb b/app/models/order.rb | |
index 8726359..092643c 100644 | |
--- a/app/models/order.rb | |
+++ b/app/models/order.rb | |
@@ -319,6 +319,12 @@ class Order < ActiveRecord::Base | |
end | |
end | |
+ def refund!(order_refunder=OrderRefunder.new(self)) | |
+ transaction do | |
+ order_refunder.refund! | |
+ end | |
+ end | |
+ | |
def self.refunded | |
with_state(:refunded).order 'orders.created_at' | |
end | |
@@ -428,26 +434,7 @@ class Order < ActiveRecord::Base | |
end | |
def before_refunded | |
- transaction do | |
- loyalty.add_credit loyalty_credit | |
- loyalty.unpunch self | |
- user.add_credit user_credit | |
- redemptions.each { |redemption| redemption.claim.add_value redemption.value } | |
- | |
- self.refund_type = case | |
- when balance.zero? then 'no_balance' | |
- when bundle.open? then 'bundle_refunded' | |
- when refund_balance.success? then 'braintree_refunded' | |
- when user.add_credit(balance) then 'user_credited' | |
- end | |
- | |
- create_refund_object! refund_type: refund_type | |
- end | |
- end | |
- | |
- def charge | |
- raise RuntimeError, "not implemented yet" | |
- puts "not implemented" | |
+ refund! | |
end | |
def interstitial_action | |
diff --git a/app/models/order_refunder.rb b/app/models/order_refunder.rb | |
new file mode 100644 | |
index 0000000..7565b19 | |
--- /dev/null | |
+++ b/app/models/order_refunder.rb | |
@@ -0,0 +1,24 @@ | |
+class OrderRefunder | |
+ def initialize(order) | |
+ @order = order | |
+ end | |
+ | |
+ delegate :balance, :bundle, :create_refund_object!, :loyalty, :loyalty_credit, :user, | |
+ :refund_balance, :redemptions, :refund_type, :user_credit, to: :@order | |
+ | |
+ def refund! | |
+ loyalty.add_credit loyalty_credit | |
+ loyalty.unpunch @order | |
+ user.add_credit user_credit | |
+ redemptions.each { |redemption| redemption.claim.add_value redemption.value } | |
+ | |
+ @order.refund_type = case | |
+ when balance.zero? then 'no_balance' | |
+ when bundle.open? then 'bundle_refunded' | |
+ when refund_balance.success? then 'braintree_refunded' | |
+ when user.add_credit(balance) then 'user_credited' | |
+ end | |
+ | |
+ create_refund_object! refund_type: refund_type | |
+ end | |
+end | |
diff --git a/test/unit/order_refunder_test.rb b/test/unit/order_refunder_test.rb | |
new file mode 100644 | |
index 0000000..f4de9cf | |
--- /dev/null | |
+++ b/test/unit/order_refunder_test.rb | |
@@ -0,0 +1,280 @@ | |
+require 'test_helper' | |
+ | |
+class Test < ActiveSupport::TestCase | |
+ context 'refund' do | |
+ setup do | |
+ stub_braintree_customer_sale_success | |
+ @order = create(:completed_order, | |
+ balance: 45.to_money, | |
+ claim_credit: 8.to_money, | |
+ earn: 9.to_money, | |
+ loyalty_credit: 3.to_money, | |
+ spend: 50.to_money, | |
+ tip: 10.to_money, | |
+ user_credit: 3.to_money) | |
+ | |
+ @loyalty = @order.loyalty.tap do |loyalty| | |
+ loyalty.credit = 5.to_money | |
+ loyalty.first_order_created_at = @order.created_at | |
+ loyalty.last_order_created_at = @order.created_at | |
+ loyalty.orders_completed_count = 1 | |
+ loyalty.savings = 15.to_money | |
+ loyalty.spend = 65.to_money | |
+ loyalty.spend_volume = 60.to_money | |
+ loyalty.tip_volume = 10.to_money | |
+ loyalty.save! | |
+ end | |
+ | |
+ @user = @order.user.tap do |user| | |
+ user.credit = 2.to_money | |
+ user.save! | |
+ end | |
+ | |
+ @bundle = create(:bundle, user: @user) | |
+ @bundle.orders << @order | |
+ | |
+ @claim_one = create(:claim) | |
+ @claim_one.value_remaining = 1.to_money | |
+ @claim_one.save! | |
+ create :redemption, claim: @claim_one, order: @order, value: 3.to_money | |
+ | |
+ @claim_two = create(:claim) | |
+ @claim_two.value_remaining = 0.to_money | |
+ @claim_two.save! | |
+ create :redemption, claim: @claim_two, order: @order, value: 5.to_money | |
+ end | |
+ | |
+ context 'when state is refunded' do | |
+ setup do | |
+ @order.state = 'refunded' | |
+ @order.refund_type = 'braintree_refunded' | |
+ @order.refunded_at = Time.zone.now | |
+ @order.save! | |
+ @original_refunded_at = @order.refunded_at | |
+ @result = @order.refund | |
+ end | |
+ | |
+ should 'not change loyalty.credit' do | |
+ assert_equal 5.to_money, @loyalty.credit | |
+ end | |
+ | |
+ should 'not change loyalty.first_order_created_at' do | |
+ assert_equal @order.created_at, @loyalty.first_order_created_at | |
+ end | |
+ | |
+ should 'not change loyalty.last_order_created_at' do | |
+ assert_equal @order.created_at, @loyalty.last_order_created_at | |
+ end | |
+ | |
+ should 'not change loyalty.savings' do | |
+ assert_equal 15.to_money, @loyalty.savings | |
+ end | |
+ | |
+ should 'not change loyalty.spend' do | |
+ assert_equal 65.to_money, @loyalty.spend | |
+ end | |
+ | |
+ should 'not change loyalty.spend_volume' do | |
+ assert_equal 60.to_money, @loyalty.spend_volume | |
+ end | |
+ | |
+ should 'not change loyalty.tip_volume' do | |
+ assert_equal 10, @loyalty.tip_volume | |
+ end | |
+ | |
+ should 'not change loyalty.orders_completed_count' do | |
+ assert_equal 1, @loyalty.orders_completed_count | |
+ end | |
+ | |
+ should 'not change user.credit' do | |
+ assert_equal 2.to_money, @user.credit | |
+ end | |
+ | |
+ should 'not change value_remaining of first claim' do | |
+ assert_equal 1.to_money, @claim_one.reload.value_remaining | |
+ end | |
+ | |
+ should 'not change value_remaining of second claim' do | |
+ assert_equal 0.to_money, @claim_two.reload.value_remaining | |
+ end | |
+ | |
+ should 'not change refund_type' do | |
+ assert_equal 'braintree_refunded', @order.refund_type | |
+ end | |
+ | |
+ should 'not change state' do | |
+ assert @order.refunded? | |
+ end | |
+ | |
+ should 'not change refunded_at' do | |
+ assert_equal @original_refunded_at, @order.refunded_at | |
+ end | |
+ | |
+ should_not_enqueue_delayed_job 'OrderRefundedJob' | |
+ | |
+ should 'return false' do | |
+ assert !@result | |
+ end | |
+ end | |
+ | |
+ context 'when state is completed' do | |
+ setup do | |
+ @order.spend = 5.to_money | |
+ @order.tip = 1.to_money | |
+ end | |
+ | |
+ context 'and balance is zero' do | |
+ setup do | |
+ @order.balance = 0.to_money | |
+ @order.refund | |
+ end | |
+ | |
+ should 'create a refund object with a correct refund type' do | |
+ assert_equal 'no_balance', @order.refund_object.refund_type | |
+ end | |
+ | |
+ should 'set refund_type to no_balance' do | |
+ assert_equal 'no_balance', @order.refund_type | |
+ end | |
+ end | |
+ | |
+ context 'and balance is nonzero' do | |
+ context 'and bundle is open' do | |
+ setup do | |
+ @order.bundle.stubs state: 'open' | |
+ @order.balance = 1.to_money | |
+ @order.refund | |
+ end | |
+ | |
+ should 'create a refund object with a correct refund type' do | |
+ assert_equal 'bundle_refunded', @order.refund_object.refund_type | |
+ end | |
+ | |
+ should 'set refund_type to bundle_refunded' do | |
+ assert_equal 'bundle_refunded', @order.refund_type | |
+ end | |
+ end | |
+ | |
+ context 'and bundle is closed' do | |
+ setup do | |
+ stub_braintree_transaction_refund_success | |
+ @order.bundle.stubs state: 'closed' | |
+ @order.balance = 1.to_money | |
+ @order.refund | |
+ end | |
+ | |
+ should 'create a refund object with a correct refund type' do | |
+ assert_equal 'braintree_refunded', @order.refund_object.refund_type | |
+ end | |
+ | |
+ should 'set refund_type to braintree_refunded' do | |
+ assert_equal 'braintree_refunded', @order.refund_type | |
+ end | |
+ end | |
+ end | |
+ | |
+ context 'and balance is nonzero and braintree refund fails and bundle is closed' do | |
+ setup do | |
+ stub_braintree_transaction_refund_validation_error | |
+ @order.bundle.stubs state: 'closed' | |
+ @order.balance = 1.to_money | |
+ @order.refund | |
+ end | |
+ | |
+ should 'add user_credit and balance to user.credit' do | |
+ assert_equal 6.to_money, @user.credit | |
+ end | |
+ | |
+ should 'create a refund object with a correct refund type' do | |
+ assert_equal 'user_credited', @order.refund_object.refund_type | |
+ end | |
+ | |
+ should 'set refund_type to user_credited' do | |
+ assert_equal 'user_credited', @order.refund_type | |
+ end | |
+ end | |
+ | |
+ context 'always' do | |
+ setup do | |
+ stub_braintree_transaction_refund_success | |
+ @time_with_zone = Time.zone.now | |
+ @order.spend = 50.to_money | |
+ @order.tip = 10.to_money | |
+ | |
+ Timecop.freeze @time_with_zone do | |
+ @result = @order.refund | |
+ end | |
+ end | |
+ | |
+ should 'add loyalty_credit to, then subtract earn from loyalty.credit' do | |
+ assert_equal 0.to_money, @loyalty.credit | |
+ end | |
+ | |
+ should 'create a refund object' do | |
+ assert @order.refund_object | |
+ end | |
+ | |
+ should 'set loyalty.first_order_created_at to nil' do | |
+ assert_nil @loyalty.first_order_created_at | |
+ end | |
+ | |
+ should 'set loyalty.last_order_created_at to nil' do | |
+ assert_nil @loyalty.last_order_created_at | |
+ end | |
+ | |
+ should 'subtract credit from loyalty.savings' do | |
+ assert_equal 0.to_money, @loyalty.savings | |
+ end | |
+ | |
+ should 'subtract total from loyalty.spend' do | |
+ assert_equal 5.to_money, @loyalty.spend | |
+ end | |
+ | |
+ should 'subtract spend from loyalty.spend_volume' do | |
+ assert_equal 10.to_money, @loyalty.spend_volume | |
+ end | |
+ | |
+ should 'subtract tip from loyalty.tip_volume' do | |
+ assert_equal 0, @loyalty.tip_volume | |
+ end | |
+ | |
+ should 'decrement loyalty.orders_completed_count by one' do | |
+ assert_equal 0, @loyalty.orders_completed_count | |
+ end | |
+ | |
+ should 'add user_credit to user.credit' do | |
+ assert_equal 5.to_money, @user.credit | |
+ end | |
+ | |
+ should 'add claim_credit to value_remaining of first claim' do | |
+ assert_equal 4.to_money, @claim_one.reload.value_remaining | |
+ end | |
+ | |
+ should 'add claim_credit to value_remaining of second claim' do | |
+ assert_equal 5.to_money, @claim_two.reload.value_remaining | |
+ end | |
+ | |
+ should 'set refund_type' do | |
+ assert_equal 'braintree_refunded', @order.refund_type | |
+ end | |
+ | |
+ should 'mark the order as refunded' do | |
+ assert @order.refunded? | |
+ end | |
+ | |
+ should 'set refunded_at' do | |
+ assert_equal @time_with_zone, @order.refunded_at | |
+ end | |
+ | |
+ should_enqueue_delayed_job 'OrderRefundedJob' do | |
+ { order_id: @order.id } | |
+ end | |
+ | |
+ should 'return true' do | |
+ assert @result | |
+ end | |
+ end | |
+ end | |
+ end | |
+ | |
+end | |
diff --git a/test/unit/order_test.rb b/test/unit/order_test.rb | |
index 27a95fa..80ffcb8 100644 | |
--- a/test/unit/order_test.rb | |
+++ b/test/unit/order_test.rb | |
@@ -1006,279 +1006,15 @@ class OrderTest < ActiveSupport::TestCase | |
end | |
end | |
- context 'refund' do | |
+ context 'refund!' do | |
setup do | |
- stub_braintree_customer_sale_success | |
- @order = create(:completed_order, | |
- balance: 45.to_money, | |
- claim_credit: 8.to_money, | |
- earn: 9.to_money, | |
- loyalty_credit: 3.to_money, | |
- spend: 50.to_money, | |
- tip: 10.to_money, | |
- user_credit: 3.to_money) | |
- | |
- @loyalty = @order.loyalty.tap do |loyalty| | |
- loyalty.credit = 5.to_money | |
- loyalty.first_order_created_at = @order.created_at | |
- loyalty.last_order_created_at = @order.created_at | |
- loyalty.orders_completed_count = 1 | |
- loyalty.savings = 15.to_money | |
- loyalty.spend = 65.to_money | |
- loyalty.spend_volume = 60.to_money | |
- loyalty.tip_volume = 10.to_money | |
- loyalty.save! | |
- end | |
- | |
- @user = @order.user.tap do |user| | |
- user.credit = 2.to_money | |
- user.save! | |
- end | |
- | |
- @bundle = create(:bundle, user: @user) | |
- @bundle.orders << @order | |
- | |
- @claim_one = create(:claim) | |
- @claim_one.value_remaining = 1.to_money | |
- @claim_one.save! | |
- create :redemption, claim: @claim_one, order: @order, value: 3.to_money | |
- | |
- @claim_two = create(:claim) | |
- @claim_two.value_remaining = 0.to_money | |
- @claim_two.save! | |
- create :redemption, claim: @claim_two, order: @order, value: 5.to_money | |
- end | |
- | |
- context 'when state is refunded' do | |
- setup do | |
- @order.state = 'refunded' | |
- @order.refund_type = 'braintree_refunded' | |
- @order.refunded_at = Time.zone.now | |
- @order.save! | |
- @original_refunded_at = @order.refunded_at | |
- @result = @order.refund | |
- end | |
- | |
- should 'not change loyalty.credit' do | |
- assert_equal 5.to_money, @loyalty.credit | |
- end | |
- | |
- should 'not change loyalty.first_order_created_at' do | |
- assert_equal @order.created_at, @loyalty.first_order_created_at | |
- end | |
- | |
- should 'not change loyalty.last_order_created_at' do | |
- assert_equal @order.created_at, @loyalty.last_order_created_at | |
- end | |
- | |
- should 'not change loyalty.savings' do | |
- assert_equal 15.to_money, @loyalty.savings | |
- end | |
- | |
- should 'not change loyalty.spend' do | |
- assert_equal 65.to_money, @loyalty.spend | |
- end | |
- | |
- should 'not change loyalty.spend_volume' do | |
- assert_equal 60.to_money, @loyalty.spend_volume | |
- end | |
- | |
- should 'not change loyalty.tip_volume' do | |
- assert_equal 10, @loyalty.tip_volume | |
- end | |
- | |
- should 'not change loyalty.orders_completed_count' do | |
- assert_equal 1, @loyalty.orders_completed_count | |
- end | |
- | |
- should 'not change user.credit' do | |
- assert_equal 2.to_money, @user.credit | |
- end | |
- | |
- should 'not change value_remaining of first claim' do | |
- assert_equal 1.to_money, @claim_one.reload.value_remaining | |
- end | |
- | |
- should 'not change value_remaining of second claim' do | |
- assert_equal 0.to_money, @claim_two.reload.value_remaining | |
- end | |
- | |
- should 'not change refund_type' do | |
- assert_equal 'braintree_refunded', @order.refund_type | |
- end | |
- | |
- should 'not change state' do | |
- assert @order.refunded? | |
- end | |
- | |
- should 'not change refunded_at' do | |
- assert_equal @original_refunded_at, @order.refunded_at | |
- end | |
- | |
- should_not_enqueue_delayed_job 'OrderRefundedJob' | |
- | |
- should 'return false' do | |
- assert !@result | |
- end | |
+ @order = Order.new | |
+ @order_refunder = stub('order_refunder', :refund!) | |
+ @order.refund!(@order_refunder) | |
end | |
- context 'when state is completed' do | |
- setup do | |
- @order.spend = 5.to_money | |
- @order.tip = 1.to_money | |
- end | |
- | |
- context 'and balance is zero' do | |
- setup do | |
- @order.balance = 0.to_money | |
- @order.refund | |
- end | |
- | |
- should 'create a refund object with a correct refund type' do | |
- assert_equal 'no_balance', @order.refund_object.refund_type | |
- end | |
- | |
- should 'set refund_type to no_balance' do | |
- assert_equal 'no_balance', @order.refund_type | |
- end | |
- end | |
- | |
- context 'and balance is nonzero' do | |
- context 'and bundle is open' do | |
- setup do | |
- @order.bundle.stubs state: 'open' | |
- @order.balance = 1.to_money | |
- @order.refund | |
- end | |
- | |
- should 'create a refund object with a correct refund type' do | |
- assert_equal 'bundle_refunded', @order.refund_object.refund_type | |
- end | |
- | |
- should 'set refund_type to bundle_refunded' do | |
- assert_equal 'bundle_refunded', @order.refund_type | |
- end | |
- end | |
- | |
- context 'and bundle is closed' do | |
- setup do | |
- stub_braintree_transaction_refund_success | |
- @order.bundle.stubs state: 'closed' | |
- @order.balance = 1.to_money | |
- @order.refund | |
- end | |
- | |
- should 'create a refund object with a correct refund type' do | |
- assert_equal 'braintree_refunded', @order.refund_object.refund_type | |
- end | |
- | |
- should 'set refund_type to braintree_refunded' do | |
- assert_equal 'braintree_refunded', @order.refund_type | |
- end | |
- end | |
- end | |
- | |
- context 'and balance is nonzero and braintree refund fails and bundle is closed' do | |
- setup do | |
- stub_braintree_transaction_refund_validation_error | |
- @order.bundle.stubs state: 'closed' | |
- @order.balance = 1.to_money | |
- @order.refund | |
- end | |
- | |
- should 'add user_credit and balance to user.credit' do | |
- assert_equal 6.to_money, @user.credit | |
- end | |
- | |
- should 'create a refund object with a correct refund type' do | |
- assert_equal 'user_credited', @order.refund_object.refund_type | |
- end | |
- | |
- should 'set refund_type to user_credited' do | |
- assert_equal 'user_credited', @order.refund_type | |
- end | |
- end | |
- | |
- context 'always' do | |
- setup do | |
- stub_braintree_transaction_refund_success | |
- @time_with_zone = Time.zone.now | |
- @order.spend = 50.to_money | |
- @order.tip = 10.to_money | |
- | |
- Timecop.freeze @time_with_zone do | |
- @result = @order.refund | |
- end | |
- end | |
- | |
- should 'add loyalty_credit to, then subtract earn from loyalty.credit' do | |
- assert_equal 0.to_money, @loyalty.credit | |
- end | |
- | |
- should 'create a refund object' do | |
- assert @order.refund_object | |
- end | |
- | |
- should 'set loyalty.first_order_created_at to nil' do | |
- assert_nil @loyalty.first_order_created_at | |
- end | |
- | |
- should 'set loyalty.last_order_created_at to nil' do | |
- assert_nil @loyalty.last_order_created_at | |
- end | |
- | |
- should 'subtract credit from loyalty.savings' do | |
- assert_equal 0.to_money, @loyalty.savings | |
- end | |
- | |
- should 'subtract total from loyalty.spend' do | |
- assert_equal 5.to_money, @loyalty.spend | |
- end | |
- | |
- should 'subtract spend from loyalty.spend_volume' do | |
- assert_equal 10.to_money, @loyalty.spend_volume | |
- end | |
- | |
- should 'subtract tip from loyalty.tip_volume' do | |
- assert_equal 0, @loyalty.tip_volume | |
- end | |
- | |
- should 'decrement loyalty.orders_completed_count by one' do | |
- assert_equal 0, @loyalty.orders_completed_count | |
- end | |
- | |
- should 'add user_credit to user.credit' do | |
- assert_equal 5.to_money, @user.credit | |
- end | |
- | |
- should 'add claim_credit to value_remaining of first claim' do | |
- assert_equal 4.to_money, @claim_one.reload.value_remaining | |
- end | |
- | |
- should 'add claim_credit to value_remaining of second claim' do | |
- assert_equal 5.to_money, @claim_two.reload.value_remaining | |
- end | |
- | |
- should 'set refund_type' do | |
- assert_equal 'braintree_refunded', @order.refund_type | |
- end | |
- | |
- should 'mark the order as refunded' do | |
- assert @order.refunded? | |
- end | |
- | |
- should 'set refunded_at' do | |
- assert_equal @time_with_zone, @order.refunded_at | |
- end | |
- | |
- should_enqueue_delayed_job 'OrderRefundedJob' do | |
- { order_id: @order.id } | |
- end | |
- | |
- should 'return true' do | |
- assert @result | |
- end | |
- end | |
+ should 'call the expected methods on order refunder' do | |
+ assert_received @order_refunder, :refund! | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment