Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only credit back allowed amount #1603

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions core/app/models/spree/payment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ def credit_allowed
amount - (offsets_total.abs + refunds.sum(:amount))
end

# The total amount this payment can be credited as a Spree::Money object
#
# @return [Spree::Money] The amount of this payment minus offets and refunds
# as a money object with the associated currency.
def credit_allowed_money
Spree::Money.new(
credit_allowed,
currency: currency
)
end

# @return [Boolean] true when this payment can be credited
def can_credit?
credit_allowed > 0
Expand Down
19 changes: 16 additions & 3 deletions core/app/models/spree/payment_method/store_credit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,16 @@ def credit(amount_in_cents, auth_code, gateway_options = {})
currency = gateway_options[:currency] || store_credit.currency
originator = gateway_options[:originator]

store_credit.credit(amount_in_cents / 100.0.to_d, auth_code, currency, action_originator: originator)
if amount_in_cents > 0
store_credit.credit(
::Money.new(amount_in_cents, currency).to_d,
auth_code,
currency,
action_originator: originator
)
else
ActiveMerchant::Billing::Response.new(true, '')
end
end

handle_action(action, :credit, auth_code)
Expand All @@ -71,8 +80,12 @@ def cancel(auth_code)
if store_credit_event.nil? || store_credit.nil?
ActiveMerchant::Billing::Response.new(false, '', {}, {})
elsif store_credit_event.capture_action?
amount_in_cents = (store_credit_event.amount * 100).round
credit(amount_in_cents, auth_code)
amount = if store_credit_event.originator_type == 'Spree::Payment'
store_credit_event.originator.credit_allowed_money.cents
else
(store_credit_event.amount * 100).round
end
credit(amount, auth_code, { originator: store_credit_event.originator })
elsif store_credit_event.authorization_action?
void(auth_code)
else
Expand Down
48 changes: 38 additions & 10 deletions core/spec/models/spree/payment_method/store_credit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,19 @@
end
end

context "when attempting to credit for zero" do
let(:credit_amount) { 0 }

it "does not credit the store credit" do
expect_any_instance_of(Spree::StoreCredit).to_not receive(:credit)
subject
end

it "returns a success response" do
expect(subject.success?).to be true
end
end

context "when the store credit isn't credited successfully" do
before { allow_any_instance_of(Spree::StoreCredit).to receive_messages(credit: false) }

Expand Down Expand Up @@ -263,19 +276,34 @@
end

context "capture event found" do
let!(:store_credit_event) {
create(:store_credit_capture_event,
authorization_code: auth_code,
amount: captured_amount,
store_credit: store_credit)
}
let!(:store_credit_event) do
create(
:store_credit_capture_event,
authorization_code: auth_code,
amount: captured_amount,
store_credit: store_credit,
originator: originator
)
end
let(:payment) { create(:payment, order: order, amount: 5) }
let(:originator) { nil }

it_behaves_like "a spree payment method"

it "refunds the capture amount" do
expect { subject }.to change{ store_credit.reload.amount_remaining }.
from(original_amount - captured_amount).
to(original_amount)
context "when originator is nil" do
it "refunds the event amount" do
expect { subject }.to change{ store_credit.reload.amount_remaining }.
from(90).to(100)
end
end

context "when the originator is the payment" do
let(:originator) { payment }

it "refunds the payment credit allowed amount" do
expect { subject }.to change{ store_credit.reload.amount_remaining }.
from(90).to(95)
end
end
end

Expand Down
47 changes: 47 additions & 0 deletions core/spec/models/spree/payment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,53 @@
end
end

describe "#credit_allowed_money" do
subject { payment.credit_allowed_money }

let(:currency) { 'USD' }
let(:order) { create :order, currency: currency }
let(:payment) do
create :payment, amount: 100, order: order, state: 'completed'
end

context "when there are no offsets" do
context "when the currency is USD" do
it "it returns the payment amount" do
expect(subject).to eq(Spree::Money.new(100, currency: 'USD'))
end
end

context "when the currency is JPY" do
let(:currency) { 'JPY' }
it "it returns the total amount" do
expect(subject).to eq(Spree::Money.new(100, currency: 'JPY'))
end
end
end

context "when there are offsets" do
before do
payment.offsets.create!(
amount: -80,
order: order,
source: payment,
state: 'completed'
)
end

it "is the difference between offsets total and payment amount in cents" do
expect(subject).to eq(Spree::Money.new(20, currency: 'USD'))
end

context "when the currency is JPY" do
let(:currency) { 'JPY' }
it "it returns the total amount minus offsets" do
expect(subject).to eq(Spree::Money.new(20, currency: 'JPY'))
end
end
end
end

describe "#can_credit?" do
it "is true if credit_allowed > 0" do
allow(payment).to receive(:credit_allowed).and_return(100)
Expand Down