mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
389 lines
12 KiB
Ruby
389 lines
12 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'system_helper'
|
|
|
|
RSpec.describe '
|
|
As an administrator
|
|
I want to manage invoices for an order
|
|
', feature: :invoices do
|
|
include WebHelper
|
|
include AuthenticationHelper
|
|
|
|
let(:user) { create(:user) }
|
|
let(:product) { create(:simple_product) }
|
|
let(:distributor) {
|
|
create(:distributor_enterprise, owner: user, charges_sales_tax: true, abn: "123456")
|
|
}
|
|
let(:order_cycle) do
|
|
create(:simple_order_cycle, name: 'One', distributors: [distributor],
|
|
variants: [product.variants.first])
|
|
end
|
|
|
|
let(:order) do
|
|
create(:order_with_totals_and_distribution,
|
|
distributor:, user:,
|
|
order_cycle:, state: 'complete',
|
|
payment_state: 'balance_due')
|
|
end
|
|
let(:customer) { order.customer }
|
|
|
|
before do
|
|
order.finalize!
|
|
login_as_admin
|
|
visit spree.edit_admin_order_path(order)
|
|
end
|
|
|
|
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 "Create or Update Invoice"
|
|
expect(page).not_to have_link "Create or Update Invoice"
|
|
}.to change { order.invoices.count }.by(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).not_to have_link "Create or Update 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 "Create or Update Invoice"
|
|
expect(page).not_to have_link "Create or Update 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 "Create or Update Invoice"
|
|
expect(page).not_to have_link "Create or Update 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
|
|
|
|
describe 'printing invoices' do
|
|
context 'when the order has no invoices' do
|
|
it 'creates an invoice for the order' do
|
|
expect(order.invoices.count).to eq 0
|
|
page.find("#links-dropdown", text: "Actions").click
|
|
click_link "Print Invoice"
|
|
# wait for PDF to open in new window
|
|
new_window = windows.last
|
|
page.within_window new_window do
|
|
expect(order.invoices.count).to eq 1
|
|
end
|
|
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 '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
|
|
expect(order.invoices.count).to eq 1
|
|
page.find("#links-dropdown", text: "Actions").click
|
|
click_link "Print Invoice"
|
|
new_window = windows.last
|
|
page.within_window new_window do
|
|
expect(order.invoices.count).to eq 1
|
|
end
|
|
expect(latest_invoice.reload.presenter.note).to eq 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
|
|
expect(order.invoices.count).to eq 1
|
|
page.find("#links-dropdown", text: "Actions").click
|
|
click_link "Print Invoice"
|
|
new_window = windows.last
|
|
page.within_window new_window do
|
|
expect(order.invoices.count).to eq 2
|
|
end
|
|
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
|
|
|
|
describe 'listing invoices' do
|
|
let(:date){ Time.current.to_date }
|
|
|
|
let(:first_invoice){ "#{distributor.id}-1" }
|
|
let(:second_invoice){ "#{distributor.id}-2" }
|
|
|
|
let(:row1){
|
|
[
|
|
I18n.l(date, format: :long),
|
|
second_invoice,
|
|
order.total,
|
|
"Active",
|
|
"Download"
|
|
].join(" ")
|
|
}
|
|
|
|
let(:row2){
|
|
[
|
|
I18n.l(date, format: :long),
|
|
first_invoice,
|
|
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
|
|
|
|
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
|
|
|
|
RSpec.describe "Invoice order states", feature: :invoices do
|
|
let(:user) { create(:user) }
|
|
let(:product) { create(:simple_product) }
|
|
let(:distributor) { create(:distributor_enterprise, owner: user, charges_sales_tax: true) }
|
|
let(:order_cycle) do
|
|
create(:simple_order_cycle, name: 'One', distributors: [distributor],
|
|
variants: [product.variants.first])
|
|
end
|
|
let(:order) do
|
|
create(:order_with_totals_and_distribution, user:, distributor:,
|
|
order_cycle:, state: 'complete',
|
|
payment_state: 'balance_due')
|
|
end
|
|
let(:customer) { order.customer }
|
|
|
|
before do
|
|
order.finalize!
|
|
|
|
login_as user
|
|
end
|
|
|
|
context "complete" do
|
|
let!(:order1) {
|
|
create(:order_with_totals_and_distribution, user:, distributor:,
|
|
order_cycle:, state: 'complete',
|
|
payment_state: 'balance_due',
|
|
customer_id: customer.id)
|
|
}
|
|
|
|
context "editing the order" do
|
|
before do
|
|
visit spree.edit_admin_order_path(order1)
|
|
end
|
|
|
|
it "displays the invoice tab" do
|
|
expect(page).to have_content "Complete".upcase
|
|
expect(page).to have_content "Invoices".upcase
|
|
end
|
|
end
|
|
|
|
context "visiting the invoices tab" do
|
|
let!(:table_header) {
|
|
[
|
|
"Date/Time",
|
|
"Invoice Number",
|
|
"Amount",
|
|
"Status",
|
|
"File",
|
|
].join(" ")
|
|
}
|
|
|
|
let(:invoice_number){ "#{order.distributor_id}-1" }
|
|
let(:table_contents) {
|
|
[
|
|
Invoice.first.created_at.strftime('%B %d, %Y').to_s,
|
|
invoice_number,
|
|
"0.0",
|
|
"Active",
|
|
"Download"
|
|
].join(" ")
|
|
}
|
|
let(:download_href) {
|
|
"#{spree.print_admin_order_path(order1)}?invoice_id=#{Invoice.last.id}"
|
|
}
|
|
|
|
before do
|
|
Spree::Config[:enterprise_number_required_on_invoices?] = false
|
|
visit spree.admin_order_invoices_path(order1)
|
|
end
|
|
|
|
it "displays the invoices table" do
|
|
# with no invoices, only the table header is displayed
|
|
expect(page).to have_css "table.index"
|
|
expect(page).to have_content "#{customer.first_name} #{customer.last_name} -"
|
|
expect(page.find("table").text).to have_content(table_header)
|
|
|
|
# the New invoice button + the warning should be visible
|
|
expect(page).to have_link "Create or Update Invoice"
|
|
expect(page).to have_content "The order has changed since the last invoice update."
|
|
click_link "Create or Update Invoice"
|
|
|
|
# and disappear after clicking
|
|
expect(page).not_to have_link "Create or Update Invoice"
|
|
expect(page).not_to have_content "The order has changed since the last invoice update."
|
|
|
|
# creating an invoice, displays a second row
|
|
expect(page.find("table").text).to have_content(table_contents)
|
|
|
|
# with a valid invoice download link
|
|
expect(page).to have_link("Download",
|
|
href: download_href)
|
|
end
|
|
|
|
context "the Create or Update Invoice button" do
|
|
context "when an ABN number is mandatory for invoices but not present" do
|
|
before do
|
|
Spree::Config[:enterprise_number_required_on_invoices?] = true
|
|
end
|
|
|
|
it "displays a warning that an ABN is required when it's clicked" do
|
|
visit spree.admin_order_invoices_path(order1)
|
|
message = accept_prompt { click_link "Create or Update Invoice" }
|
|
distributor = order1.distributor
|
|
expect(message)
|
|
.to eq "#{distributor.name} must have a valid ABN before invoices can be used."
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "resumed" do
|
|
let!(:order2) {
|
|
create(:order_with_totals_and_distribution, user:, distributor:,
|
|
order_cycle:, state: 'resumed',
|
|
payment_state: 'balance_due')
|
|
}
|
|
before do
|
|
visit spree.edit_admin_order_path(order2)
|
|
end
|
|
|
|
it "displays the invoice tab" do
|
|
expect(page).to have_content "Resumed".upcase
|
|
expect(page).to have_content "Invoices".upcase
|
|
end
|
|
end
|
|
|
|
context "canceled" do
|
|
let!(:order3) {
|
|
create(:order_with_totals_and_distribution, user:, distributor:,
|
|
order_cycle:, state: 'canceled',
|
|
payment_state: 'balance_due')
|
|
}
|
|
before do
|
|
visit spree.edit_admin_order_path(order3)
|
|
end
|
|
|
|
it "displays the invoice tab" do
|
|
expect(page).to have_content "Cancelled".upcase
|
|
expect(page).to have_content "Invoices".upcase
|
|
end
|
|
end
|
|
|
|
context "cart" do
|
|
let!(:order_empty) {
|
|
create(:order_with_line_items, user:, distributor:, order_cycle:,
|
|
line_items_count: 0)
|
|
}
|
|
before do
|
|
visit spree.edit_admin_order_path(order_empty)
|
|
end
|
|
|
|
it "should not display the invoice tab" do
|
|
expect(page).to have_content "Cart".upcase
|
|
expect(page).not_to have_content "Invoices".upcase
|
|
end
|
|
end
|
|
|
|
context "payment" do
|
|
let!(:order4) do
|
|
create(:order_ready_for_payment, user:, distributor:,
|
|
order_cycle:,
|
|
payment_state: 'balance_due')
|
|
end
|
|
before do
|
|
visit spree.edit_admin_order_path(order4)
|
|
end
|
|
|
|
it "should not display the invoice tab" do
|
|
expect(page).to have_content "Payment".upcase
|
|
expect(page).not_to have_content "Invoices".upcase
|
|
end
|
|
end
|
|
end
|