From dafd797a028ccb189147f3092c4f2d14d40234fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81s=20Coca?= Date: Fri, 26 Jul 2024 15:18:08 -0500 Subject: [PATCH] Added support for refunding invoices and line items --- lib/recurly/invoice.rb | 33 +++++++++++++- spec/recurly/invoice_spec.rb | 87 ++++++++++++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/lib/recurly/invoice.rb b/lib/recurly/invoice.rb index 00851ebae..cac806c93 100644 --- a/lib/recurly/invoice.rb +++ b/lib/recurly/invoice.rb @@ -249,6 +249,25 @@ def refund_amount(amount_in_cents = nil, refund_method = 'credit_first', options ) end + # Refunds the invoice for a specific percentage. + # + # @return [Invoice, false] Invoice if successful, false if the invoice isn't + # refundable. + # @raise [Error] If the refund fails. + # @param percentage [Integer, nil] The percentage to refund from the invoice. + # @param refund_method ["credit_first", "transaction_first", "all_transaction", "all_credit"] The method used to refund. + # @param external_refund [true, false] Designates that the refund transactions created are manual. + # @param credit_customer_notes [String] Adds notes to refund credit invoice. + # @param payment_method [String] Creates the manual transactions with this payment method. Allowed if *external_refund* is true. + # @param description [String] Sets this value as the *transaction_note* on the manual transactions created. Allowed if *external_refund* is true. + # @param refunded_at [DateTime] Sets this value as the *collected_at* on the manual transactions created. Allowed if *external_refund* is true. + def refund_percentage(percentage = nil, refund_method = 'credit_first', options = {}) + return false unless link? :refund + self.class.from_response( + follow_link :refund, :body => refund_percentage_to_xml(percentage, refund_method, options) + ) + end + def xml_keys super - ['currency'] end @@ -285,6 +304,16 @@ def refund_amount_to_xml(amount_in_cents = nil, refund_method = nil, options = { builder.to_s end + def refund_percentage_to_xml(percentage = nil, refund_method = nil, options = {}) + builder = XML.new("") + builder.add_element 'refund_method', refund_method + builder.add_element 'percentage', percentage + options.each do |k, v| + builder.add_element k.to_s, v + end + builder.to_s + end + def refund_line_items_to_xml(line_items = nil, refund_method = nil, options = {}) builder = XML.new("") builder.add_element 'refund_method', refund_method @@ -296,8 +325,10 @@ def refund_line_items_to_xml(line_items = nil, refund_method = nil, options = {} line_items.each do |line_item| adj_node = node.add_element 'adjustment' adj_node.add_element 'uuid', line_item[:adjustment].uuid - adj_node.add_element 'quantity', line_item[:quantity] + adj_node.add_element 'quantity', line_item[:quantity] if line_item.key?(:quantity) adj_node.add_element('quantity_decimal', line_item[:quantity_decimal]) if line_item.key?(:quantity_decimal) + adj_node.add_element 'percentage', line_item[:percentage] if line_item.key?(:percentage) + adj_node.add_element 'amount_in_cents', line_item[:amount_in_cents] if line_item.key?(:amount_in_cents) adj_node.add_element 'prorate', line_item[:prorate] end builder.to_s diff --git a/spec/recurly/invoice_spec.rb b/spec/recurly/invoice_spec.rb index 155a6e11e..fb30c87b3 100644 --- a/spec/recurly/invoice_spec.rb +++ b/spec/recurly/invoice_spec.rb @@ -162,6 +162,22 @@ adjustment.quantity_remaining.must_equal 1 end end + + it "creates a refund invoice for the line items refunded with amount in cents" do + line_items = @invoice.line_items.values.map do |adjustment| + { adjustment: adjustment, amount_in_cents: 100, prorate: false } + end + refund_invoice = @invoice.refund line_items + refund_invoice.must_be_instance_of Invoice + end + + it "creates a refund invoice for the line items refunded with percentage" do + line_items = @invoice.line_items.values.map do |adjustment| + { adjustment: adjustment, percentage: 77, prorate: false } + end + refund_invoice = @invoice.refund line_items + refund_invoice.must_be_instance_of Invoice + end end describe "#refund_to_xml" do @@ -178,6 +194,38 @@ 'credit_firstCredit NotestruecheckCheck no. 123456782018-12-01T00:00:00+00:0017500charge11false' ) end + + it "must serialize line_items with amount_in_cents" do + line_items = @invoice.line_items.values.map do |adjustment| + { adjustment: adjustment, amount_in_cents: 100, prorate: false } + end + options = { + credit_customer_notes: 'Credit Notes', + external_refund: true, + payment_method: 'check', + description: 'Check no. 12345678', + refunded_at: DateTime.new(2018, 12, 1, 0, 0, 0) + } + @invoice.send(:refund_line_items_to_xml, line_items, 'credit_first', options).must_equal( + 'credit_firstCredit NotestruecheckCheck no. 123456782018-12-01T00:00:00+00:00charge1100false' + ) + end + + it "must serialize line_items with percentage" do + line_items = @invoice.line_items.values.map do |adjustment| + { adjustment: adjustment, percentage: 77, prorate: false } + end + options = { + credit_customer_notes: 'Credit Notes', + external_refund: true, + payment_method: 'check', + description: 'Check no. 12345678', + refunded_at: DateTime.new(2018, 12, 1, 0, 0, 0) + } + @invoice.send(:refund_line_items_to_xml, line_items, 'credit_first', options).must_equal( + 'credit_firstCredit NotestruecheckCheck no. 123456782018-12-01T00:00:00+00:00charge177false' + ) + end end end @@ -189,8 +237,8 @@ @invoice = Invoice.find 'refundable-invoice' end - describe "#refund" do - it "creates a refund invoice for the line items refunded" do + describe "#refund_amount" do + it "creates a refund invoice for the line items refunded using amount" do refund_invoice = @invoice.refund_amount 1000 refund_invoice.must_be_instance_of Invoice refund_invoice.original_invoices.must_be_instance_of Recurly::Resource::Pager @@ -198,7 +246,7 @@ end end - describe "#refund_to_xml" do + describe "#refund_amount_to_xml" do it "must serialize amount_in_cents" do options = { credit_customer_notes: 'Credit Notes', @@ -215,6 +263,39 @@ end end + describe "percentage refund" do + before do + stub_api_request :get, 'invoices/refundable-invoice', 'invoices/show-200-refundable' + stub_api_request :post, 'invoices/refundable-invoice/refund', 'invoices/refund_amount-201' + + @invoice = Invoice.find 'refundable-invoice' + end + + describe "#refund_percentage" do + it "creates a refund invoice for the line items refunded using percentage" do + refund_invoice = @invoice.refund_percentage 50 + refund_invoice.must_be_instance_of Invoice + refund_invoice.original_invoices.must_be_instance_of Recurly::Resource::Pager + refund_invoice.amount_remaining_in_cents.must_equal 100 + end + end + + describe "#refund_percentage_to_xml" do + it "must serialize percentage" do + options = { + credit_customer_notes: 'Credit Notes', + external_refund: true, + payment_method: 'check', + description: 'Check no. 12345678', + refunded_at: DateTime.new(2018, 12, 1, 0, 0, 0) + } + @invoice.send(:refund_percentage_to_xml, 50, 'credit_first', options).must_equal( + 'credit_first50Credit NotestruecheckCheck no. 123456782018-12-01T00:00:00+00:00' + ) + end + end + end + describe "failed_refund" do before do stub_api_request :get, 'invoices/refundable-invoice', 'invoices/show-200-refundable'