diff --git a/app/models/invoice.rb b/app/models/invoice.rb index b86d362b5b..b66b0c5ba5 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -5,6 +5,7 @@ class Invoice < ApplicationRecord serialize :data, Hash before_validation :serialize_order after_create :cancel_previous_invoices + default_scope { order(created_at: :desc) } def presenter @presenter ||= Invoice::DataPresenter.new(self) diff --git a/app/models/invoice/data_presenter.rb b/app/models/invoice/data_presenter.rb index 65cffe82f6..0245d2dd5b 100644 --- a/app/models/invoice/data_presenter.rb +++ b/app/models/invoice/data_presenter.rb @@ -4,8 +4,8 @@ class Invoice class DataPresenter attr_reader :invoice - delegate :data, :date, to: :invoice - delegate :number, to: :invoice, prefix: true + delegate :data, to: :invoice + delegate :number, :date, to: :invoice, prefix: true FINALIZED_NON_SUCCESSFUL_STATES = %w(canceled returned).freeze @@ -79,12 +79,12 @@ class Invoice end.sort_by { |tax| tax[:rate_amount] } end - def all_tax_adjustments - all_eligible_adjustments.select { |a| a.originator_type == 'Spree::TaxRate' } + def display_date + I18n.l(invoice_date.to_date, format: :long) end - def invoice_date - date + def all_tax_adjustments + all_eligible_adjustments.select { |a| a.originator_type == 'Spree::TaxRate' } end def paid? diff --git a/app/services/order_invoice_comparator.rb b/app/services/order_invoice_comparator.rb index 24c02fced8..bd19f9dabe 100644 --- a/app/services/order_invoice_comparator.rb +++ b/app/services/order_invoice_comparator.rb @@ -77,7 +77,7 @@ class OrderInvoiceComparator end def latest_invoice - @latest_invoice ||= invoices.last.presenter + @latest_invoice ||= invoices.first.presenter end def serialize_for_invoice diff --git a/app/views/spree/admin/invoices/_invoices_table.html.haml b/app/views/spree/admin/invoices/_invoices_table.html.haml index 7d312a7139..4c876319cd 100644 --- a/app/views/spree/admin/invoices/_invoices_table.html.haml +++ b/app/views/spree/admin/invoices/_invoices_table.html.haml @@ -12,7 +12,7 @@ - tr_id = spree_dom_id(invoice) %tr{:class => tr_class, "data-hook" => "invoice_row", :id => tr_id} %td.align-center.created_at - = pretty_time(invoice.date) + = invoice.presenter.display_date %td.align-center.label = invoice.number %td.align-center.label diff --git a/spec/models/invoice/data_presenter_spec.rb b/spec/models/invoice/data_presenter_spec.rb new file mode 100644 index 0000000000..864044d502 --- /dev/null +++ b/spec/models/invoice/data_presenter_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Invoice::DataPresenter do + context "#display_date" do + let(:invoice) { double(:invoice, date: '2023-08-01') } + + let(:presenter) { Invoice::DataPresenter.new(invoice) } + it "prints in a format" do + expect(presenter.display_date).to eq "August 01, 2023" + end + end +end diff --git a/spec/system/admin/order_spec.rb b/spec/system/admin/order_spec.rb index 37b0043c00..93acf8be30 100644 --- a/spec/system/admin/order_spec.rb +++ b/spec/system/admin/order_spec.rb @@ -1044,7 +1044,7 @@ describe ' let(:table_contents) { [ - Invoice.first.created_at.strftime('%B %d, %Y 12:00 AM').to_s, + Invoice.first.created_at.strftime('%B %d, %Y').to_s, "1", "0.0", "Active", diff --git a/spec/system/admin/orders/invoices_spec.rb b/spec/system/admin/orders/invoices_spec.rb index cdd3a8de6e..26b8644a6b 100644 --- a/spec/system/admin/orders/invoices_spec.rb +++ b/spec/system/admin/orders/invoices_spec.rb @@ -4,7 +4,7 @@ require 'system_helper' describe ' As an administrator - I want to create an invoice for an order + I want to manage invoices for an order ' do include WebHelper include AuthenticationHelper @@ -32,73 +32,116 @@ describe ' visit spree.edit_admin_order_path(order) end - context 'when the order has no invoices' do - it 'creates an invoice for the order' do - click_link 'Invoices' + describe 'creating invoices' do + context 'when the order has no invoices' do + it 'creates an invoice for the order' do + click_link 'Invoices' - expect { - click_link 'New Invoice' - expect(page).to have_no_link "New Invoice" - }.to change { order.invoices.count }.by(1) + expect { + click_link 'New Invoice' + expect(page).to have_no_link "New Invoice" + }.to change { order.invoices.count }.by(1) - invoice = order.invoices.first - expect(invoice.cancelled).to eq false - expect(invoice.number).to eq 1 + invoice = order.invoices.first + expect(invoice.cancelled).to eq false + expect(invoice.number).to eq 1 + end + end + + context 'when the order has an invoice' do + let!(:latest_invoice){ create(:invoice, order:, number: 1, cancelled: false) } + + context 'order not updated since latest invoice' do + it 'should not render new invoice button' do + click_link 'Invoices' + expect(page).to_not have_link 'New Invoice' + end + end + + # For reference check: + # https://docs.google.com/spreadsheets/d/1hOM6UL4mWeRCFLcDQ3fTkbhbUQ2WvIUCCA1IerDBtUA/edit#gid=0 + context 'order updated since latest invoice' do + context 'changes require regenerating' do + let(:new_note){ 'new note' } + before do + order.update!(note: new_note) + end + + it 'updates the lastest invoice for the order' do + click_link 'Invoices' + expect { + click_link 'New Invoice' + expect(page).to have_no_link "New Invoice" + }.to change { order.reload.invoices.count }.by(0) + .and change { latest_invoice.reload.presenter.note }.from("").to(new_note) + + expect(latest_invoice.reload.cancelled).to eq false + end + end + + context 'changes require generating a new invoice' do + before do + order.line_items.first.update!(quantity: 2) + end + + it 'creates a new invoice for the order' do + click_link 'Invoices' + expect { + click_link 'New Invoice' + expect(page).to have_no_link "New Invoice" + }.to change { order.reload.invoices.count }.by(1) + + expect(latest_invoice.reload.cancelled).to eq true + expect(latest_invoice.presenter.sorted_line_items.first.quantity).to eq 1 + + new_invoice = order.invoices.first # first invoice is the latest + expect(new_invoice.cancelled).to eq false + expect(new_invoice.number).to eq 2 + expect(new_invoice.presenter.sorted_line_items.first.quantity).to eq 2 + end + end + end end end - context 'when the order has an invoice' do - let!(:latest_invoice){ create(:invoice, order:, number: 1, cancelled: false) } + describe 'listing invoices' do + let(:date){ Time.current.to_date } - context 'order not updated since latest invoice' do - it 'should not render new invoice button' do - click_link 'Invoices' - expect(page).to_not have_link 'New Invoice' - end + let(:row1){ + [ + I18n.l(date, format: :long), + "2", + order.total, + "Active", + "Download" + ].join(" ") + } + + let(:row2){ + [ + I18n.l(date, format: :long), + "1", + order.total, + "Cancelled", + "Download" + ].join(" ") + } + + let(:table_content){ + [ + row1, + row2 + ].join(" ") + } + + before do + create(:invoice, order:, number: 1, cancelled: true, date:) + create(:invoice, order:, number: 2, cancelled: false, date:) end - # For reference check: - # https://docs.google.com/spreadsheets/d/1hOM6UL4mWeRCFLcDQ3fTkbhbUQ2WvIUCCA1IerDBtUA/edit#gid=0 - context 'order updated since latest invoice' do - context 'changes require regenerating' do - let(:new_note){ 'new note' } - before do - order.update!(note: new_note) - end - - it 'updates the lastest invoice for the order' do - click_link 'Invoices' - expect { - click_link 'New Invoice' - expect(page).to have_no_link "New Invoice" - }.to change { order.reload.invoices.count }.by(0) - .and change { latest_invoice.reload.presenter.note }.from("").to(new_note) - - expect(latest_invoice.reload.cancelled).to eq false - end - end - - context 'changes require generating a new invoice' do - before do - order.line_items.first.update!(quantity: 2) - end - - it 'creates a new invoice for the order' do - click_link 'Invoices' - expect { - click_link 'New Invoice' - expect(page).to have_no_link "New Invoice" - }.to change { order.reload.invoices.count }.by(1) - - expect(latest_invoice.reload.cancelled).to eq true - expect(latest_invoice.presenter.sorted_line_items.first.quantity).to eq 1 - - new_invoice = order.invoices.last - expect(new_invoice.cancelled).to eq false - expect(new_invoice.number).to eq 2 - expect(new_invoice.presenter.sorted_line_items.first.quantity).to eq 2 - end - end + it 'should list the invoices on the reverse order of creation' do + click_link 'Invoices' + expect(page).to have_content table_content end end end