diff --git a/app/models/solidus_paypal_braintree/source.rb b/app/models/solidus_paypal_braintree/source.rb index 517dfcf3..47848316 100644 --- a/app/models/solidus_paypal_braintree/source.rb +++ b/app/models/solidus_paypal_braintree/source.rb @@ -32,7 +32,11 @@ def can_capture?(payment) end def can_void?(payment) - !payment.failed? && !payment.void? + return false unless payment.response_code + transaction = braintree_client.transaction.find(payment.response_code) + Gateway::VOIDABLE_STATUSES.include?(transaction.status) + rescue Braintree::NotFoundError + false end def can_credit?(payment) diff --git a/spec/models/solidus_paypal_braintree/source_spec.rb b/spec/models/solidus_paypal_braintree/source_spec.rb index afd2b589..4483532b 100644 --- a/spec/models/solidus_paypal_braintree/source_spec.rb +++ b/spec/models/solidus_paypal_braintree/source_spec.rb @@ -49,25 +49,51 @@ end end - describe "#can_void?" do - subject { described_class.new.can_void?(payment) } + describe '#can_void?' do + let(:payment_source) { described_class.new } + let(:payment) { build(:payment) } - context "when the payment failed" do - let(:payment) { build(:payment, state: "failed") } + let(:transaction_response) do + double(status: Braintree::Transaction::Status::SubmittedForSettlement) + end - it { is_expected.not_to be } + let(:transaction_request) do + double(find: transaction_response) end - context "when the payment is already voided" do - let(:payment) { build(:payment, state: "void") } + subject { payment_source.can_void?(payment) } - it { is_expected.not_to be } + before do + allow(payment_source).to receive(:braintree_client) do + double(transaction: transaction_request) + end end - context "when the payment is completed" do - let(:payment) { build(:payment, state: "completed") } + context 'when transaction id is not present' do + let(:payment) { build(:payment, response_code: nil) } - it { is_expected.to be } + it { is_expected.to be(false) } + end + + context 'when transaction has voidable status' do + it { is_expected.to be(true) } + end + + context 'when transaction has non voidable status' do + let(:transaction_response) do + double(status: Braintree::Transaction::Status::Settled) + end + + it { is_expected.to be(false) } + end + + context 'when transaction is not found at Braintreee' do + before do + allow(transaction_request).to \ + receive(:find).and_raise(Braintree::NotFoundError) + end + + it { is_expected.to be(false) } end end