diff --git a/app/controllers/eis_billing/invoices_controller.rb b/app/controllers/eis_billing/invoices_controller.rb new file mode 100644 index 000000000..0b4ce1281 --- /dev/null +++ b/app/controllers/eis_billing/invoices_controller.rb @@ -0,0 +1,71 @@ +module EisBilling + class InvoicesController < BaseController + TYPE = 'PaymentOrders::EveryPay'.freeze + + before_action :load_invoice, only: :update + + def update + if @invoice.update(modified_params) + payment_orders_handler + + render json: { + message: 'Invoice data was successfully updated' + }, status: :ok + else + render json: { + error: @message.errors.full_messages + }, status: :unprocessable_entity + end + end + + private + + def payment_orders_handler + if @invoice.payment_orders.present? + return if (@invoice.paid? && status == 'paid') || (@invoice.cancelled? && status == 'cancelled') + + if status == 'cancelled' || status == 'failed' + @invoice.cancel_manualy + elsif status == 'paid' + @invoice.autobind_manually + end + else + return unless status == 'paid' + + @invoice.autobind_manually + end + end + + def status + case params[:invoice][:status] + when 'paid' + 'paid' + when 'cancelled' + 'cancelled' + when 'failed' + 'failed' + else + 'issued' + end + end + + def load_invoice + @invoice = Invoice.find_by(number: params[:invoice][:invoice_number]) + + if @invoice.nil? + render json: { + error: { + message: "Invoice with #{params[:invoice][:invoice_number]} number not found" + } + }, status: :not_found and return + end + end + + def modified_params + { + in_directo: params[:invoice][:in_directo], + e_invoice_sent_at: params[:invoice][:sent_at_omniva] + } + end + end +end diff --git a/app/controllers/eis_billing/payment_status_controller.rb b/app/controllers/eis_billing/payment_status_controller.rb index 015eed64a..383d47a1d 100644 --- a/app/controllers/eis_billing/payment_status_controller.rb +++ b/app/controllers/eis_billing/payment_status_controller.rb @@ -3,19 +3,20 @@ module EisBilling TYPE = 'PaymentOrders::EveryPay'.freeze def update - payment_status = define_payment_status(params[:payment_state]) invoice = Invoice.find_by(number: params[:order_reference]) - return if invoice.paid? + if invoice.paid? + render json: { message: 'Invoice already paid' }, status: :ok + else + invoice.process_payment( + payment_type: TYPE, + everypay_response: params, + payment_status: define_payment_status(params[:payment_state]), + sum: params[:standing_amount], + transaction_time: params[:transaction_time] + ) - bank = create_bank_transfer(invoice: invoice, sum: params[:standing_amount], paid_at: params[:transaction_time]) - create_payment_order(invoice: invoice, everypay_response: params, payment_status: payment_status) - bank.bind_invoice(params[:order_reference]) - - respond_to do |format| - format.json do - render status: :ok, content_type: 'application/json', layout: false, json: { message: 'ok' } - end + render json: { message: 'Payment is proccessing' }, status: :ok end end @@ -26,30 +27,5 @@ module EisBilling :failed end - - def create_payment_order(invoice:, everypay_response:, payment_status:) - payment = PaymentOrder.new - payment.type = TYPE - payment.invoice = invoice - payment.response = everypay_response - payment.status = payment_status - payment.save - - payment - end - - def create_bank_transfer(invoice:, sum:, paid_at:) - bank = BankTransaction.new - bank.description = invoice.order - bank.reference_no = invoice.reference_no - bank.currency = invoice.currency - bank.iban = invoice.seller_iban - bank.sum = sum - bank.paid_at = paid_at - bank.buyer_name = invoice.buyer_name - bank.save - - bank - end end end diff --git a/app/models/concerns/invoice/cancellable.rb b/app/models/concerns/invoice/cancellable.rb index 9b1c6435b..29c09f47c 100644 --- a/app/models/concerns/invoice/cancellable.rb +++ b/app/models/concerns/invoice/cancellable.rb @@ -31,4 +31,22 @@ module Invoice::Cancellable def not_cancelled? !cancelled? end + + def cancel_manualy + account_activity = AccountActivity.find_by(invoice_id: id) + account_activity_dup = account_activity.dup + account_activity_dup.sum = -account_activity.sum.to_i + account_activity_dup.save + account_activity.update(invoice_id: nil) + account_activity_dup.update(invoice_id: nil) + mark_cancelled_payment_order + account_activity.save && account_activity_dup.save + end + + private + + def mark_cancelled_payment_order + payment_order = payment_orders.last + payment_order.update(notes: 'Cancelled') + end end diff --git a/app/models/concerns/invoice/payable.rb b/app/models/concerns/invoice/payable.rb index 855ea8f41..79e02c92d 100644 --- a/app/models/concerns/invoice/payable.rb +++ b/app/models/concerns/invoice/payable.rb @@ -23,4 +23,34 @@ module Invoice::Payable def unpaid? !paid? end + + def process_payment(**options) + payment = options[:payment_type].constantize.new(invoice: self) + payment.response = options[:everypay_response] + payment.status = options[:payment_status] + payment.save! + + bank_transaction = payment.base_transaction(sum: options[:sum], + paid_at: options[:transaction_time] || Time.zone.now, + buyer_name: buyer_name) + bank_transaction.bind_invoice(number) + end + + def autobind_manually + return if paid? + + bank_statement = BankStatement.new( + bank_code: Setting.registry_bank_code, + iban: Setting.registry_iban + ) + bank_statement.bank_transactions.build( + description: description, + sum: total, + reference_no: reference_no, + paid_at: Time.zone.now.to_date, + currency: 'EUR' + ) + bank_statement.save! + bank_statement.bind_invoices(manual: true) + end end diff --git a/config/routes.rb b/config/routes.rb index d8d52f322..581a572f9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,7 @@ Rails.application.routes.draw do put '/directo_response', to: 'directo_response#update', as: 'directo_response' put '/e_invoice_response', to: 'e_invoice_response#update', as: 'e_invoice_response' post '/lhv_connect_transactions', to: 'lhv_connect_transactions#create', as: 'lhv_connect_transactions' + resource :invoices, only: [:update] end namespace :epp do diff --git a/db/structure.sql b/db/structure.sql index 6286053ce..b10129d30 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -4447,6 +4447,7 @@ CREATE INDEX index_log_domains_on_object ON public.log_domains USING gin (object -- +<<<<<<< HEAD -- Name: index_log_domains_on_object_changes; Type: INDEX; Schema: public; Owner: - -- @@ -4454,6 +4455,8 @@ CREATE INDEX index_log_domains_on_object_changes ON public.log_domains USING gin -- +======= +>>>>>>> creating sync with billing -- Name: index_log_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: - -- diff --git a/test/integration/eis_billing/invoices_test.rb b/test/integration/eis_billing/invoices_test.rb new file mode 100644 index 000000000..2edbc533d --- /dev/null +++ b/test/integration/eis_billing/invoices_test.rb @@ -0,0 +1,306 @@ +require 'test_helper' + +class StubAuthorization < ApplicationController + skip_authorization_check + + def authorized + true + end +end + +EisBilling::BaseController = StubAuthorization + +class EInvoiceResponseTest < ApplicationIntegrationTest + setup do + sign_in users(:api_bestnames) + @invoice = invoices(:one) + + response_message = { + message: 'got it' + } + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_status') + .to_return(status: 200, body: response_message.to_json, headers: {}) + end + + test 'it should update status of invoice if payment order is existed' do + @invoice.update(total: 120.0) + @invoice.reload + + incoming_params = { + invoice: { + invoice_number: @invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 120.0, + status: 'paid', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + @invoice.account_activity.delete && @invoice.reload + + assert_equal @invoice.payment_orders.pluck(:status), %w[issued issued] + put eis_billing_invoices_path, params: incoming_params + @invoice.reload + @invoice.payment_orders.each(&:reload) + + invoice = Invoice.find(@invoice.id) + assert_equal invoice.payment_orders.pluck(:status), %w[issued issued paid] + end + + test 'it should update invoice data as directo and omniva' do + incoming_params = { + invoice: { + invoice_number: @invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 270.0, + status: 'unpaid', + in_directo: true, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + assert_equal @invoice.payment_orders.pluck(:status), %w[issued issued] + assert_nil @invoice.e_invoice_sent_at + refute @invoice.in_directo + + put eis_billing_invoices_path, params: incoming_params + + @invoice.payment_orders.each(&:reload) + @invoice.reload + + assert_equal @invoice.payment_orders.pluck(:status), %w[issued issued] + assert @invoice.in_directo + assert_not_nil @invoice.e_invoice_sent_at + end + + test 'it should create new payment order if payment order and activity are missing, but status has paid status' do + invoice = invoices(:one) + + invoice.payment_orders.destroy_all and invoice.account_activity.destroy + invoice.update(total: 120.0) + invoice.reload + + incoming_params = { + invoice: { + invoice_number: invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 120.0, + status: 'paid', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + assert invoice.payment_orders.empty? + assert_nil invoice.account_activity + + put eis_billing_invoices_path, params: incoming_params + + invoice.reload + invoice.payment_orders.each(&:reload) + + assert_equal invoice.payment_orders.count, 1 + assert invoice.payment_orders.first.paid? + assert invoice.account_activity + end + + test 'it should ignore payment order creation if payment status is not paid and payment order not existed' do + incoming_params = { + invoice: { + invoice_number: @invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 270.0, + status: 'cancelled', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + @invoice.payment_orders.destroy_all and @invoice.account_activity.destroy + @invoice.reload + + assert @invoice.payment_orders.empty? + assert_nil @invoice.account_activity + + put eis_billing_invoices_path, params: incoming_params and @invoice.reload + + assert @invoice.payment_orders.empty? + assert_nil @invoice.account_activity + end + + test 'it should add balance if payment order mark as paid' do + invoice = invoices(:one) + item = invoice.items.first + + invoice.payment_orders.destroy_all and invoice.account_activity.destroy + invoice.update(total: 120.0) && invoice.reload + item.update(price: 100.0) && item.reload + + incoming_params = { + invoice: { + invoice_number: invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 120.0, + status: 'paid', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + assert invoice.payment_orders.empty? + assert_nil invoice.account_activity + + account = invoice.buyer.accounts.first + + assert_equal account.balance.to_f, 100.0 + + put eis_billing_invoices_path, params: incoming_params + + invoice.reload + invoice.payment_orders.each(&:reload) + account.reload + + assert_equal invoice.payment_orders.count, 1 + assert invoice.payment_orders.first.paid? + assert invoice.account_activity + + assert_equal account.balance.to_f, 200.0 + end + + test 'should change nothing if invoice is already paid' do + assert @invoice.account_activity.present? + assert @invoice.payment_orders.present? + + account = @invoice.buyer.accounts.first + assert_equal account.balance.to_f, 100.0 + assert @invoice.paid? + + incoming_params = { + invoice: { + invoice_number: @invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: @invoice.total, + status: 'paid', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + put eis_billing_invoices_path, params: incoming_params + account.reload + + assert_equal account.balance.to_f, 100.0 + end + + test 'it should decrease balance and again add if user change paid invoice to cancel and then again to paid' do + invoice = invoices(:one) + item = invoice.items.first + + invoice.payment_orders.destroy_all and invoice.account_activity.destroy + invoice.update(total: 120.0) && invoice.reload + item.update(price: 100.0) && item.reload + + add_balance_params = { + invoice: { + invoice_number: invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 120.0, + status: 'paid', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + assert invoice.payment_orders.empty? + assert_nil invoice.account_activity + + account = invoice.buyer.accounts.first + + assert_equal account.balance.to_f, 100.0 + + put eis_billing_invoices_path, params: add_balance_params + + invoice.reload + invoice.payment_orders.each(&:reload) + account.reload + + assert_equal invoice.payment_orders.count, 1 + assert invoice.payment_orders.first.paid? + assert invoice.account_activity + + assert_equal account.balance.to_f, 200.0 + + decrease_balance_params = { + invoice: { + invoice_number: invoice.number, + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 120.0, + status: 'cancelled', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + put eis_billing_invoices_path, params: decrease_balance_params + invoice.reload + invoice.payment_orders.each(&:reload) + account.reload + + assert_equal account.balance.to_f, 100.0 + end + + test 'it should return an error if invoice not existing' do + incoming_params = { + invoice: { + invoice_number: 'nonexisted-invoice', + initiator: 'registry', + payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349', + transaction_amount: 120.0, + status: 'paid', + in_directo: false, + everypay_response: { + 'some' => 'some' + }, + sent_at_omniva: Time.zone.now - 10.minutes + } + } + + put eis_billing_invoices_path, params: incoming_params + registry_response = JSON.parse(response.body).with_indifferent_access[:error] + + assert_equal registry_response[:message], 'Invoice with nonexisted-invoice number not found' + end +end diff --git a/test/integration/eis_billing/payment_status_test.rb b/test/integration/eis_billing/payment_status_test.rb index 69c50e120..f13a1d0a1 100644 --- a/test/integration/eis_billing/payment_status_test.rb +++ b/test/integration/eis_billing/payment_status_test.rb @@ -9,10 +9,7 @@ class PaymentStatusTest < ApplicationIntegrationTest Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true) end - def shoudl_update_buyer_balance - assert @invoice.paid? - assert_equal @invoice.buyer.balance.to_f, 100.0 - + test 'should mark an invoice as paid' do payload = { payment_state: 'settled', order_reference: @unpaid.number, @@ -20,13 +17,57 @@ class PaymentStatusTest < ApplicationIntegrationTest transaction_time: Time.zone.now, } - put eis_billing_payment_status_path, params: payload + item = @unpaid.items.first - @invoice.reload - @invoice.buyer.reload - @registrar.reload + refute @unpaid.paid? + assert_equal @unpaid.buyer.balance.to_f, 100.0 + assert_equal item.price, 5.0 + + put eis_billing_payment_status_path, params: payload + @unpaid.reload + assert_equal @unpaid.buyer.balance.to_f, 105.0 + end + + test 'ignore additonal callbacks if invoice is already paid' do + payload = { + payment_state: 'settled', + order_reference: @unpaid.number, + standing_amount: @unpaid.total, + transaction_time: Time.zone.now, + } + + item = @unpaid.items.first + + refute @unpaid.paid? + assert_equal @unpaid.buyer.balance.to_f, 100.0 + assert_equal item.price, 5.0 + + put eis_billing_payment_status_path, params: payload + @unpaid.reload + assert_equal @unpaid.buyer.balance.to_f, 105.0 + assert @unpaid.paid? + + put eis_billing_payment_status_path, params: payload + @unpaid.reload + + assert_equal @unpaid.buyer.balance.to_f, 105.0 + assert @unpaid.paid? + end + + test 'send callback to already paid invoice' do + payload = { + payment_state: 'settled', + order_reference: @invoice.number, + standing_amount: @invoice.total, + transaction_time: Time.zone.now, + } assert @invoice.paid? assert_equal @invoice.buyer.balance.to_f, 100.0 + + put eis_billing_payment_status_path, params: payload + @invoice.reload + assert_equal @invoice.buyer.balance.to_f, 100.0 + assert @invoice.paid? end end diff --git a/test/models/invoice_test.rb b/test/models/invoice_test.rb index 344af9dcc..18d5c79d2 100644 --- a/test/models/invoice_test.rb +++ b/test/models/invoice_test.rb @@ -6,6 +6,8 @@ class InvoiceTest < ActiveSupport::TestCase setup do @invoice = invoices(:one) Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_status') + .to_return(status: :ok, headers: {}) end def test_fixture_is_valid @@ -124,32 +126,32 @@ class InvoiceTest < ActiveSupport::TestCase transaction.sum = 250 invoice_n = Invoice.order(number: :desc).last.number - stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator") + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator') .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}", headers: {}) - stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator") - .to_return(status: 200, body: "{\"everypay_link\":\"http://link.test\"}", headers: {}) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator') + .to_return(status: 200, body: '{"everypay_link":"http://link.test"}', headers: {}) - stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response"). - to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {}) + stub_request(:put, 'https://registry:3000/eis_billing/e_invoice_response') + .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now - 10.minutes}\"}", headers: {}) - stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice"). - to_return(status: 200, body: "", headers: {}) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/e_invoice/e_invoice') + .to_return(status: 200, body: '', headers: {}) invoice = Invoice.create_from_transaction!(transaction) assert_equal 250, invoice.total invoice_n = Invoice.order(number: :desc).last.number - stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator"). - to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 4}\"}", headers: {}) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator') + .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 4}\"}", headers: {}) transaction.sum = 146.88 invoice = Invoice.create_from_transaction!(transaction) assert_equal 146.88, invoice.total invoice_n = Invoice.order(number: :desc).last.number - stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator"). - to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 5}\"}", headers: {}) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator') + .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 5}\"}", headers: {}) transaction.sum = 0.99 invoice = Invoice.create_from_transaction!(transaction) @@ -158,14 +160,14 @@ class InvoiceTest < ActiveSupport::TestCase def test_emails_invoice_after_creating_topup_invoice invoice_n = Invoice.order(number: :desc).last.number - stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator"). - to_return(status: 200, body: "{\"everypay_link\":\"http://link.test\"}", headers: {}) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator') + .to_return(status: 200, body: '{"everypay_link":"http://link.test"}', headers: {}) - stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response"). - to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {}) + stub_request(:put, 'https://registry:3000/eis_billing/e_invoice_response') + .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now - 10.minutes}\"}", headers: {}) - stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice"). - to_return(status: 200, body: "", headers: {}) + stub_request(:post, 'https://eis_billing_system:3000/api/v1/e_invoice/e_invoice') + .to_return(status: 200, body: '', headers: {}) registrar = registrars(:bestnames) transaction = bank_transactions(:one).dup @@ -179,4 +181,73 @@ class InvoiceTest < ActiveSupport::TestCase Invoice.create_from_transaction!(transaction) end end + + def test_create_payment_order + everypay_response = { + 'some' => 'some' + } + @invoice.payment_orders.delete_all + @invoice.account_activity.delete and @invoice.reload + assert @invoice.payment_orders.empty? + assert_nil @invoice.account_activity + + @invoice.process_payment(payment_type: 'PaymentOrders::EveryPay', + everypay_response: everypay_response, + payment_status: 'paid', + sum: @invoice.total, + transaction_time: Time.zone.now - 10.minutes - 23.seconds) + + @invoice.reload + + assert_equal @invoice.payment_orders.count, 1 + assert @invoice.account_activity.present? + end + + def test_should_raise_error_if_bill_already_paid + everypay_response = { + 'some' => 'some' + } + assert @invoice.payment_orders.present? + + assert_raises(ActiveRecord::RecordInvalid) do + @invoice.process_payment(payment_type: 'PaymentOrders::EveryPay', + everypay_response: everypay_response, + payment_status: 'paid', + sum: @invoice.total, + transaction_time: Time.zone.now - 10.minutes - 23.seconds) + end + end + + def test_should_manually_autobin_invoice + @invoice.payment_orders.destroy_all && @invoice.account_activity.destroy + @invoice.reload + + account = @invoice.buyer.accounts.first + item = @invoice.items.first + + assert @invoice.payment_orders.empty? + assert @invoice.account_activity.nil? + assert_equal account.balance.to_f, 100.0 + assert_equal item.price, 5.0 + + @invoice.autobind_manually + @invoice.reload + account.reload + + assert_equal account.balance.to_f, 105.0 + assert @invoice.payment_orders.present? + assert @invoice.account_activity.present? + end + + def test_cannot_to_increase_balance_already_paid_invoice_by_manually_autobind + assert @invoice.paid? + + account = @invoice.buyer.accounts.first + assert_equal account.balance.to_f, 100.0 + + @invoice.autobind_manually + @invoice.reload + + assert_equal account.balance.to_f, 100.0 + end end