implement the invoice data generator

This commit is contained in:
Mohamed ABDELLANI
2023-04-20 07:40:01 +01:00
committed by Konrad
parent d9efd10ac0
commit fa14dc370b
4 changed files with 146 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
class Invoice::LineItemSerializer < ActiveModel::Serializer
attributes :added_tax, :currency, :included_tax, :price_with_adjustments, :quantity, :variant_id
attributes :id, :added_tax, :currency, :included_tax, :price_with_adjustments, :quantity, :variant_id
has_one :variant, serializer: Invoice::VariantSerializer
end

View File

@@ -0,0 +1,64 @@
class InvoiceDataGenerator
attr :order
def initialize(order)
@order = order
end
# Give the latest invoice's data and the currect order data
# we want to generate a new invoice data that:
# 1. keeps the immutable attributes
# 2. include the update details from the order
def generate
return new_data if old_data.nil?
# keep the immutable attributes
update_order_attributes
update_line_items
update_payment_methods
new_data
end
private
def update_order_attributes
[:distributor, :order_cycle, :customer].each do |attribute|
new_data[attribute] = old_data[attribute]
end
return unless new_data[:shipping_method_id] == old_data[:shipping_method_id]
new_data[:shipping_method] = old_data[:shipping_method]
end
# if the variant, product or supplier details are updated
# we want to keep the old details in the invoice
def update_line_items
new_data[:sorted_line_items].each do |new_line_item|
old_line_item = old_data[:sorted_line_items].find { |li| li[:id] == new_line_item[:id] }
next if old_line_item.nil?
new_line_item[:variant] = old_line_item[:variant]
end
end
# if the payment method is updated,
# we want to keep the old payment method in the invoice
def update_payment_methods
new_data[:payments].each do |new_payment|
old_payment = old_data[:payments].find { |p| p[:id] == new_payment[:id] }
next if old_payment.nil?
new_payment[:payment_method] = old_payment[:payment_method]
end
end
def new_data
@new_data ||= order.serialize_for_invoice
end
def old_data
@old_data ||= order.invoices&.last.data
end
end

View File

@@ -0,0 +1,79 @@
# frozen_string_literal: true
require 'spec_helper'
describe InvoiceDataGenerator do
describe '#generate' do
let!(:order) { create(:completed_order_with_fees) }
let!(:latest_invoice){ create(:invoice, order: order, data: order.serialize_for_invoice) }
let(:new_invoice_data) {
InvoiceDataGenerator.new(order).generate
}
let(:new_invoice) { create(:invoice, order: order, data: new_invoice_data) }
let(:new_invoice_presenter) { new_invoice.presenter }
context "mutable attribute updated" do
it "should reflect the changes" do
new_note = "This is an updated note"
order.update!(note: new_note)
expect(new_invoice_presenter.order_note).to eq(new_note)
end
end
context "immutable attribute updated" do
let!(:old_distributor_name) { latest_invoice.presenter.distributor.abn }
it "should not reflect the changes" do
order.distributor.update!(name: 'NEW ABN')
expect(new_invoice_presenter.distributor.abn).to eq(old_distributor_name)
end
end
context "shipping method" do
it "should keep the old sm details if the shipping method id doesn't change" do
shipping_method = order.shipping_method
old_shipping_method_name = shipping_method.name
shipping_method.update!(name: "NEW NAME")
expect(new_invoice_presenter.shipping_method.name).to eq(old_shipping_method_name)
end
it "should update the sm details if the shipping method id is updated" do
new_shipping_method = create(:shipping_method)
order.distributor.shipping_methods << new_shipping_method
order.select_shipping_method new_shipping_method.id
expect(new_invoice_presenter.shipping_method.name).to eq(new_shipping_method.name)
end
end
context "line items" do
it "should reflect the changes" do
line_item = order.line_items.first
new_quantity = line_item.quantity + 1
line_item.update!(quantity: new_quantity)
expect(new_invoice_presenter.sorted_line_items.first.quantity).to eq(new_quantity)
end
it "should not reflect variant changes" do
line_item = order.line_items.first
old_variant_name = line_item.variant.display_name
line_item.variant.update!(display_name: "NEW NAME")
expect(new_invoice_presenter.sorted_line_items.first.variant.display_name).to eq(old_variant_name)
end
end
context "order without invoices" do
let!(:order) { create(:completed_order_with_fees) }
let(:new_invoice_data) {
InvoiceDataGenerator.new(order).generate
}
it "should generate a new invoice" do
expect(new_invoice_data).to eql order.serialize_for_invoice
end
end
end
end

View File

@@ -5,7 +5,7 @@ require 'spec_helper'
describe OrderInvoiceComparator do
describe '#can_generate_new_invoice?' do
let!(:order) { create(:completed_order_with_fees) }
let!(:invoice){ create(:invoice, order: order) }
let!(:invoice){ create(:invoice, order: order, data: order.serialize_for_invoice) }
let(:current_state_invoice){ order.current_state_invoice }
let(:subject) {
OrderInvoiceComparator.new.can_generate_new_invoice?(current_state_invoice, invoice)
@@ -47,7 +47,7 @@ describe OrderInvoiceComparator do
describe '#can_update_latest_invoice?' do
let!(:order) { create(:completed_order_with_fees) }
let!(:invoice){ create(:invoice, order: order) }
let!(:invoice){ create(:invoice, order: order, data: order.serialize_for_invoice) }
let(:current_state_invoice){ order.current_state_invoice }
let(:subject) {
OrderInvoiceComparator.new.can_update_latest_invoice?(current_state_invoice, invoice)