diff --git a/app/controllers/eis_billing/invoices_controller.rb b/app/controllers/eis_billing/invoices_controller.rb index 81ff9b9888..23a64c83ff 100644 --- a/app/controllers/eis_billing/invoices_controller.rb +++ b/app/controllers/eis_billing/invoices_controller.rb @@ -1,15 +1,8 @@ module EisBilling class InvoicesController < BaseController - TYPE = 'PaymentOrders::EveryPay'.freeze - PAID = 'paid'.freeze - CANCELLED = 'cancelled'.freeze - ISSUED = 'unpaid'.freeze - FAILED = 'failed'.freeze - before_action :load_invoice, only: :update def update - # if @invoice.update(modified_params) && payment_orders_handler state = InvoiceStateMachine.new(invoice: @invoice, status: params[:status]) if @invoice.update(modified_params) && state.call render json: { @@ -26,42 +19,6 @@ def update private - # def payment_orders_handler - # return false if @invoice.cancelled? && status.paid? || @invoice.cancelled? && status.issued? - # return false if @invoice.paid? && (status.failed? || status.cancelled?) - - # case - # when @invoice.paid? && status.paid? - # true - # when @invoice.unpaid? && status.issued? - # true - # when @invoice.cancelled? && (status.cancelled? || status.failed?) - # true - # when status.issued? - # @invoice.cancel_manualy - # when status.paid? - # @invoice.autobind_manually - # else - # @invoice.cancel - # end - # end - - # def status - # status = case params[:status] - # when 'paid' - # 'paid' - # when 'cancelled' - # 'cancelled' - # when 'failed' - # 'failed' - # else - # 'unpaid' - # end - - # Struct.new(:paid?, :cancelled?, :issued?, :failed?) - # .new(status == PAID, status == CANCELLED, status == ISSUED, status == FAILED) - # end - def load_invoice @invoice = Invoice.find_by(number: params[:invoice][:invoice_number]) return if @invoice.present? diff --git a/app/models/invoice_state_machine.rb b/app/models/invoice_state_machine.rb index 210263a579..cd1886665f 100644 --- a/app/models/invoice_state_machine.rb +++ b/app/models/invoice_state_machine.rb @@ -1,5 +1,3 @@ -# enum status: %i[unpaid paid cancelled failed] - class InvoiceStateMachine attr_reader :invoice, :status @@ -24,21 +22,24 @@ def call private def mark_as_paid - return push_error unless invoice.payable? || invoice.paid? + return push_error unless invoice.payable? + return true if invoice.paid? invoice.autobind_manually invoice end def mark_as_cancel - return push_error unless invoice.cancellable? || invoice.cancelled? + return push_error unless invoice.cancellable? + return true if invoice.cancelled? invoice.cancel invoice end def mark_as_unpaid - return push_error if invoice.paid? || !invoice.cancellable? + return push_error if invoice.paid? && invoice.payment_orders.last.payment_reference? || invoice.cancelled? + return true unless invoice.paid? invoice.cancel_manualy invoice diff --git a/app/models/payment_order.rb b/app/models/payment_order.rb index fd66843476..5e7069e1be 100644 --- a/app/models/payment_order.rb +++ b/app/models/payment_order.rb @@ -64,6 +64,10 @@ def self.supported_method?(name, shortname: false) false end + def payment_reference? + response && response['payment_reference'].present? + end + def base_transaction(sum:, paid_at:, buyer_name:) BankTransaction.new( description: invoice.order, diff --git a/app/models/payment_orders/every_pay.rb b/app/models/payment_orders/every_pay.rb index 15526e4d7d..2695c20e0f 100644 --- a/app/models/payment_orders/every_pay.rb +++ b/app/models/payment_orders/every_pay.rb @@ -30,10 +30,6 @@ def valid_response_from_intermediary? valid_hmac? && valid_amount? && valid_account? end - def payment_reference? - response['payment_reference'].present? - end - def settled_payment? SUCCESSFUL_PAYMENT.include?(response['payment_state']) end diff --git a/test/models/invoice_state_machinte_test.rb b/test/models/invoice_state_machinte_test.rb new file mode 100644 index 0000000000..319da1aa2d --- /dev/null +++ b/test/models/invoice_state_machinte_test.rb @@ -0,0 +1,105 @@ +require 'test_helper' + +class InvoiceTest < ActiveSupport::TestCase + include ActionMailer::TestHelper + + setup do + @invoice = invoices(:one) + @unpaid = invoices(:unpaid) + + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_status') + .with( + body: '{"invoice_number":2,"status":"paid"}' + ) + .to_return(status: 200, body: '', headers: {}) + end + + def test_unpaid_invoice_can_be_change_status_to_paid + assert !@unpaid.paid? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'paid').call + @unpaid.reload + + assert @unpaid.paid? + end + + def test_no_any_errors_if_invoice_with_unpaid_status_set_again_unpaid + assert !@unpaid.paid? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'unpaid').call + @unpaid.reload + + assert !@unpaid.paid? + assert @unpaid.errors.empty? + end + + def test_only_unpaid_invoice_can_be_cancelled + assert !@unpaid.paid? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'cancelled').call + @unpaid.reload + + assert @unpaid.cancelled? + + assert @invoice.paid? + InvoiceStateMachine.new(invoice: @invoice, status: 'cancelled').call + @invoice.reload + + assert_equal @invoice.errors.full_messages.join, 'Inavalid state cancelled' + assert @invoice.errors.present? + end + + def test_cancelled_invoiced_cannot_be_unpaid + assert !@unpaid.paid? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'cancelled').call + @unpaid.reload + + assert @unpaid.cancelled? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'unpaid').call + @unpaid.reload + + assert @unpaid.cancelled? + + assert @unpaid.errors.present? + assert_equal @unpaid.errors.full_messages.join, 'Inavalid state unpaid' + end + + def test_if_paid_invoice_not_have_response_from_everypay_it_can_be_unpaid_back + assert !@unpaid.paid? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'paid').call + @unpaid.reload + + assert @unpaid.paid? + assert_nil @unpaid.payment_orders.last.payment_reference? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'unpaid').call + @unpaid.reload + + assert !@unpaid.paid? + end + + def test_if_paid_invoice_has_response_from_everypay_it_cannot_be_rollback + assert !@unpaid.paid? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'paid').call + @unpaid.reload + + assert @unpaid.paid? + payment_order = @unpaid.payment_orders.last + payment_order.response = {} + payment_order.response[:payment_reference] = 'responsefromeveryapy' + payment_order.save && payment_order.reload + + assert @unpaid.payment_orders.last.payment_reference? + + InvoiceStateMachine.new(invoice: @unpaid, status: 'unpaid').call + @unpaid.reload + + assert @unpaid.paid? + assert @unpaid.errors.present? + assert_equal @unpaid.errors.full_messages.join, 'Inavalid state unpaid' + end +end