From f24af3feb0d01bd4b0ec36a3c8e7ff3176cb783c Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Tue, 11 Jul 2023 09:41:01 +0100 Subject: [PATCH 01/12] extract invoice printing logic into a seperated method --- app/jobs/bulk_invoice_job.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/jobs/bulk_invoice_job.rb b/app/jobs/bulk_invoice_job.rb index fba3dde99f..b16443fb6b 100644 --- a/app/jobs/bulk_invoice_job.rb +++ b/app/jobs/bulk_invoice_job.rb @@ -5,13 +5,7 @@ class BulkInvoiceJob < ApplicationJob delegate :render, to: ActionController::Base def perform(order_ids, filepath, options = {}) - pdf = CombinePDF.new - - sorted_orders(order_ids).each do |order| - invoice = renderer.render_to_string(order) - - pdf << CombinePDF.parse(invoice) - end + sorted_orders(order_ids).each(&method(:generate_invoice)) ensure_directory_exists filepath @@ -32,6 +26,11 @@ class BulkInvoiceJob < ApplicationJob @renderer ||= InvoiceRenderer.new end + def generate_invoice order + invoice = renderer.render_to_string(order) + pdf << CombinePDF.parse(invoice) + end + def broadcast(filepath, channel) file_id = filepath.split("/").last.split(".").first @@ -47,4 +46,8 @@ class BulkInvoiceJob < ApplicationJob def ensure_directory_exists(filepath) FileUtils.mkdir_p(File.dirname(filepath)) end + + def pdf + @pdf ||= CombinePDF.new + end end From 4f6ab69add7cdf5667dc569d7c7cb0ac7dba1d1d Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Tue, 11 Jul 2023 10:42:31 +0100 Subject: [PATCH 02/12] implement OrderInvoiceGenerator service --- .../spree/admin/invoices_controller.rb | 21 +------ app/services/order_invoice_generator.rb | 34 +++++++++++ spec/services/order_invoice_generator_spec.rb | 60 +++++++++++++++++++ 3 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 app/services/order_invoice_generator.rb create mode 100644 spec/services/order_invoice_generator_spec.rb diff --git a/app/controllers/spree/admin/invoices_controller.rb b/app/controllers/spree/admin/invoices_controller.rb index c304a63697..397b1a050f 100644 --- a/app/controllers/spree/admin/invoices_controller.rb +++ b/app/controllers/spree/admin/invoices_controller.rb @@ -23,20 +23,7 @@ module Spree def generate @order = Order.find_by(number: params[:order_id]) authorize! :invoice, @order - - @comparator = OrderInvoiceComparator.new(@order) - if @comparator.can_generate_new_invoice? - @order.invoices.create!( - date: Time.zone.today, - number: @order.invoices.count + 1, - data: invoice_data - ) - elsif @comparator.can_update_latest_invoice? - @order.invoices.last.update!( - date: Time.zone.today, - data: invoice_data - ) - end + OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice redirect_back(fallback_location: spree.admin_dashboard_path) end @@ -56,12 +43,6 @@ module Spree render json: { created: false }, status: :unprocessable_entity end end - - protected - - def invoice_data - @invoice_data ||= InvoiceDataGenerator.new(@order).generate - end end end end diff --git a/app/services/order_invoice_generator.rb b/app/services/order_invoice_generator.rb new file mode 100644 index 0000000000..4e02ccf487 --- /dev/null +++ b/app/services/order_invoice_generator.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class OrderInvoiceGenerator + def initialize(order) + @order = order + end + + def generate_or_update_latest_invoice + if comparator.can_generate_new_invoice? + order.invoices.create!( + date: Time.zone.today, + number: order.invoices.count + 1, + data: invoice_data + ) + elsif comparator.can_update_latest_invoice? + order.invoices.last.update!( + date: Time.zone.today, + data: invoice_data + ) + end + end + + private + + attr_reader :order + + def comparator + @comparator ||= OrderInvoiceComparator.new(order) + end + + def invoice_data + @invoice_data ||= InvoiceDataGenerator.new(order).generate + end +end diff --git a/spec/services/order_invoice_generator_spec.rb b/spec/services/order_invoice_generator_spec.rb new file mode 100644 index 0000000000..852de2028a --- /dev/null +++ b/spec/services/order_invoice_generator_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe OrderInvoiceGenerator do + let!(:order) { create(:completed_order_with_fees) } + let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } + let!(:latest_invoice){ + create(:invoice, + order:, + data: invoice_data_generator.serialize_for_invoice) + } + + let(:instance) { described_class.new(order) } + let(:comparator){ double("OrderInvoiceComparator") } + + before do + allow(instance).to receive(:comparator).and_return(comparator) + end + + describe "#generate_or_update_latest_invoice" do + let(:subject) { instance.generate_or_update_latest_invoice } + context "when can generate new invoice" do + before do + expect(comparator).to receive(:can_generate_new_invoice?).and_return(true) + end + + it "should create a new invoice" do + expect(instance).to receive(:invoice_data) + expect{ subject }.to change{ order.invoices.count }.by(1) + expect(order.invoices.order('created_at desc').first.number).to eq(2) + end + end + + context "can update latest invoice" do + before do + allow(comparator).to receive(:can_generate_new_invoice?).and_return(false) + allow(comparator).to receive(:can_update_latest_invoice?).and_return(true) + order.update!(note: "This is an updated note") + end + + it "should update the latest invoice" do + expect{ subject }.to change{ latest_invoice.reload.data } + .and change{ order.invoices.count }.by(0) + end + end + + context "when can't generate new invoice or update latest invoice" do + before do + allow(comparator).to receive(:can_generate_new_invoice?).and_return(false) + allow(comparator).to receive(:can_update_latest_invoice?).and_return(false) + end + + it "should not create or update invoices" do + expect(instance).not_to receive(:invoice_data) + expect{ subject }.to change{ order.invoices.count }.by(0) + end + end + end +end From c921250d68b09bc7de5eaf307e08df1cb4a0cfc7 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Wed, 12 Jul 2023 08:58:35 +0100 Subject: [PATCH 03/12] implement Spree::Order#invoiceable? This will be used to filter the orders when running bulk print --- app/models/spree/order.rb | 4 ++++ spec/models/spree/order_spec.rb | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index 6ba226f222..470e88ac8e 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -208,6 +208,10 @@ module Spree completed_at.present? end + def invoiceable? + complete? || resumed? + end + # Indicates whether or not the user is allowed to proceed to checkout. # Currently this is implemented as a check for whether or not there is at # least one LineItem in the Order. Feel free to override this logic in your diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index e73de877a0..ca7bccfdc1 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -140,6 +140,23 @@ describe Spree::Order do end end + context "#invoiceable?" do + it "should return true if the order is completed" do + allow(order).to receive_messages(complete?: true) + expect(order.invoiceable?).to be_truthy + end + + it "should return true if the order is resumed" do + allow(order).to receive_messages(resumed?: true) + expect(order.invoiceable?).to be_truthy + end + + it "should return false if the order is neither completed nor resumed" do + allow(order).to receive_messages(complete?: false, resumed?: false) + expect(order.invoiceable?).to be_falsy + end + end + context "checking if order is paid" do context "payment_state is paid" do before { allow(order).to receive_messages payment_state: 'paid' } From 687760046b671f84003ba1284d54ccf53c33315f Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Wed, 12 Jul 2023 09:48:26 +0100 Subject: [PATCH 04/12] update the bulk invoice job to print invoiceable orders the invoices feature is enabled: 1. we filter non-invoiceable order 2. for each invoiceable order, we check if we need to generate a new invoice or update the latest invoice --- app/jobs/bulk_invoice_job.rb | 14 +++++-- spec/jobs/bulk_invoice_job_spec.rb | 66 +++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/app/jobs/bulk_invoice_job.rb b/app/jobs/bulk_invoice_job.rb index b16443fb6b..796a6365c4 100644 --- a/app/jobs/bulk_invoice_job.rb +++ b/app/jobs/bulk_invoice_job.rb @@ -5,7 +5,9 @@ class BulkInvoiceJob < ApplicationJob delegate :render, to: ActionController::Base def perform(order_ids, filepath, options = {}) - sorted_orders(order_ids).each(&method(:generate_invoice)) + orders = sorted_orders(order_ids) + orders = orders.filter(&:invoiceable?) if OpenFoodNetwork::FeatureToggle.enabled?(:invoices) + orders.each(&method(:generate_invoice)) ensure_directory_exists filepath @@ -26,8 +28,14 @@ class BulkInvoiceJob < ApplicationJob @renderer ||= InvoiceRenderer.new end - def generate_invoice order - invoice = renderer.render_to_string(order) + def generate_invoice(order) + renderer_data = if OpenFoodNetwork::FeatureToggle.enabled?(:invoices) + OrderInvoiceGenerator.new(order).generate_or_update_latest_invoice + order.invoices.first.presenter + else + order + end + invoice = renderer.render_to_string(renderer_data) pdf << CombinePDF.parse(invoice) end diff --git a/spec/jobs/bulk_invoice_job_spec.rb b/spec/jobs/bulk_invoice_job_spec.rb index d783e88321..130e70cfbf 100644 --- a/spec/jobs/bulk_invoice_job_spec.rb +++ b/spec/jobs/bulk_invoice_job_spec.rb @@ -3,19 +3,73 @@ require 'spec_helper' describe BulkInvoiceJob do - let(:order1) { build(:order, id: 1) } - let(:order2) { build(:order, id: 2) } - let(:order3) { build(:order, id: 3) } - - let(:order_ids) { [3, 1, 2] } - subject { BulkInvoiceJob.new(order_ids, "/tmp/file/path") } describe "#sorted_orders" do + let(:order1) { build(:order, id: 1) } + let(:order2) { build(:order, id: 2) } + let(:order3) { build(:order, id: 3) } + let(:order_ids) { [3, 1, 2] } + it "returns results in their original order" do expect(Spree::Order).to receive(:where).and_return([order1, order2, order3]) expect(subject.__send__(:sorted_orders, order_ids)).to eq [order3, order1, order2] end end + + context "when invoices are enabled" do + before do + Flipper.enable(:invoices) + end + + describe "#perform" do + let(:order1) { create(:order) } + let(:order2) { create(:order) } + let(:order3) { create(:order) } + let(:order_ids) { [order1.id, order2.id, order3.id] } + it "should generate invoices for invoiceable orders only" do + expect(subject).to receive(:sorted_orders).with(order_ids).and_return([order1, order2, + order3]) + expect(order1).to receive(:invoiceable?).and_return(true) + expect(order2).to receive(:invoiceable?).and_return(false) + expect(order3).to receive(:invoiceable?).and_return(true) + + [order1, order3].each do |order| + expect(subject).to receive(:generate_invoice).with(order) + end + expect(subject).not_to receive(:generate_invoice).with(order2) + + subject.perform(order_ids, "/tmp/file/path") + end + end + + describe "#generate_invoice" do + let(:order) { create(:completed_order_with_totals) } + let(:order_ids){ [order.id] } + let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } + let!(:invoice){ + create(:invoice, order:, + data: invoice_data_generator.serialize_for_invoice) + } + let(:generator){ double("generator") } + let(:renderer){ double("renderer") } + let(:printed_invoice_string){ "printed invoice string" } + + before do + expect(OrderInvoiceGenerator).to receive(:new).with(order).and_return(generator) + expect(subject).to receive(:renderer).and_return(renderer) + end + + it "should call the renderer with the invoice presenter" do + expect(generator).to receive(:generate_or_update_latest_invoice) + expect(renderer).to receive(:render_to_string).with(invoice.presenter) + .and_return(printed_invoice_string) + expect(order).to receive(:invoices).and_return([invoice]) + expect(CombinePDF).to receive(:parse).with(printed_invoice_string) + + subject.__send__(:generate_invoice, order) + end + end + end end From 5ae2545918e3f5f40a150ce1275f499d791f95b6 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Thu, 13 Jul 2023 17:57:45 +0100 Subject: [PATCH 05/12] Update app/jobs/bulk_invoice_job.rb Co-authored-by: David Cook --- app/jobs/bulk_invoice_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/bulk_invoice_job.rb b/app/jobs/bulk_invoice_job.rb index 796a6365c4..b7f0012018 100644 --- a/app/jobs/bulk_invoice_job.rb +++ b/app/jobs/bulk_invoice_job.rb @@ -6,7 +6,7 @@ class BulkInvoiceJob < ApplicationJob def perform(order_ids, filepath, options = {}) orders = sorted_orders(order_ids) - orders = orders.filter(&:invoiceable?) if OpenFoodNetwork::FeatureToggle.enabled?(:invoices) + orders.filter!(&:invoiceable?) if OpenFoodNetwork::FeatureToggle.enabled?(:invoices) orders.each(&method(:generate_invoice)) ensure_directory_exists filepath From 7daa4d3a631bf330841985518e470af180fa4876 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Wed, 12 Jul 2023 11:32:38 +0100 Subject: [PATCH 06/12] simplify filtering condition to select only invoiceable orders on OrdersReflex --- app/reflexes/admin/orders_reflex.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/reflexes/admin/orders_reflex.rb b/app/reflexes/admin/orders_reflex.rb index 7e722a2705..311cab117f 100644 --- a/app/reflexes/admin/orders_reflex.rb +++ b/app/reflexes/admin/orders_reflex.rb @@ -72,7 +72,7 @@ module Admin def send_invoices(params) count = 0 editable_orders.where(id: params[:bulk_ids]).find_each do |o| - next unless o.distributor.can_invoice? && (o.resumed? || o.complete?) + next unless o.distributor.can_invoice? && o.invoiceable? Spree::OrderMailer.invoice_email(o.id).deliver_later count += 1 From 9b80676d7d2aa23c7e60367fbc81e06a0676e145 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Wed, 12 Jul 2023 11:49:42 +0100 Subject: [PATCH 07/12] update the logic to send invoice When the invoices feature is enabled, for every order, we check if 1. a new invoice must be generated 2. or, the latest invoice needs to be updated the invoice rendrer input depends on the invoices flag. if the feature is enabled, the input is supposed to be an invoice presenter --- app/mailers/spree/order_mailer.rb | 9 +++++++- spec/mailers/order_mailer_spec.rb | 37 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/mailers/spree/order_mailer.rb b/app/mailers/spree/order_mailer.rb index a2fda5d94f..9495566974 100644 --- a/app/mailers/spree/order_mailer.rb +++ b/app/mailers/spree/order_mailer.rb @@ -48,7 +48,14 @@ module Spree def invoice_email(order_or_order_id) @order = find_order(order_or_order_id) - pdf = InvoiceRenderer.new.render_to_string(@order) + renderer_data = if OpenFoodNetwork::FeatureToggle.enabled?(:invoices) + OrderInvoiceGenerator.new(@order).generate_or_update_latest_invoice + @order.invoices.first.presenter + else + @order + end + + pdf = InvoiceRenderer.new.render_to_string(renderer_data) attach_file("invoice-#{@order.number}.pdf", pdf) I18n.with_locale valid_locale(@order.user) do diff --git a/spec/mailers/order_mailer_spec.rb b/spec/mailers/order_mailer_spec.rb index 9a2d3c4066..86b7d96b50 100644 --- a/spec/mailers/order_mailer_spec.rb +++ b/spec/mailers/order_mailer_spec.rb @@ -216,4 +216,41 @@ describe Spree::OrderMailer do end end end + + describe "#invoice_email" do + subject(:email) { described_class.invoice_email(order) } + let(:order) { create(:completed_order_with_totals) } + let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } + let!(:invoice){ + create(:invoice, order:, + data: invoice_data_generator.serialize_for_invoice) + } + + let(:generator){ double(:generator) } + let(:renderer){ double(:renderer) } + before do + allow(OrderInvoiceGenerator).to receive(:new).with(order).and_return(generator) + allow(InvoiceRenderer).to receive(:new).and_return(renderer) + end + context "When invoices feature is not enabled" do + it "should call the invoice render with order as argument" do + expect(generator).not_to receive(:generate_or_update_latest_invoice) + expect(order).not_to receive(:invoices) + expect(renderer).to receive(:render_to_string).with(order) + email.deliver_now + end + end + + context "When invoices feature is enabled" do + before do + Flipper.enable(:invoices) + end + it "should call the invoice renderer with invoice's presenter as argument" do + expect(generator).to receive(:generate_or_update_latest_invoice) + expect(order).to receive(:invoices).and_return([invoice]) + expect(renderer).to receive(:render_to_string).with(invoice.presenter) + email.deliver_now + end + end + end end From c89c8a69bc5696cc2edc3eb994ac0b83ecd207ae Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Thu, 13 Jul 2023 18:24:57 +0100 Subject: [PATCH 08/12] optimize OrderMailer#invoice_email spec Check if the email was sent without raising an error Check if the email has an attached pdf --- spec/mailers/order_mailer_spec.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/mailers/order_mailer_spec.rb b/spec/mailers/order_mailer_spec.rb index 86b7d96b50..5637978b16 100644 --- a/spec/mailers/order_mailer_spec.rb +++ b/spec/mailers/order_mailer_spec.rb @@ -228,6 +228,8 @@ describe Spree::OrderMailer do let(:generator){ double(:generator) } let(:renderer){ double(:renderer) } + let(:attachment_filename){ "invoice-#{order.number}.pdf" } + let(:deliveries){ ActionMailer::Base.deliveries } before do allow(OrderInvoiceGenerator).to receive(:new).with(order).and_return(generator) allow(InvoiceRenderer).to receive(:new).and_return(renderer) @@ -236,8 +238,13 @@ describe Spree::OrderMailer do it "should call the invoice render with order as argument" do expect(generator).not_to receive(:generate_or_update_latest_invoice) expect(order).not_to receive(:invoices) - expect(renderer).to receive(:render_to_string).with(order) - email.deliver_now + expect(renderer).to receive(:render_to_string).with(order).and_return("invoice") + expect { + email.deliver_now + }.to_not raise_error + expect(deliveries.count).to eq(1) + expect(deliveries.first.attachments.count).to eq(1) + expect(deliveries.first.attachments.first.filename).to eq(attachment_filename) end end From 2fb112aecdfd64f916f6eec7b0e8a991acacca86 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Fri, 14 Jul 2023 09:30:18 +0100 Subject: [PATCH 09/12] import BulkInvoiceJob#perform spec 1. remove the mocks 2. test the content of the generated pdf 3. remove the test of private methods --- config/locales/en.yml | 5 +++ spec/jobs/bulk_invoice_job_spec.rb | 60 ++++++++++-------------------- 2 files changed, 24 insertions(+), 41 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 9a5333c7d3..1af585fb03 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4108,6 +4108,11 @@ See the %{link} to find out more about %{sitename}'s features and to start using shipping: "Shipping" order_number: "Order Number" invoice_number: "Invoice Number" + payments_list: + date_time: "Date/time" + payment_method: "Payment method" + payment_state: "Payment state" + amount: "Amount" note: note_label: "Note:" no_note_present: "No note provided." diff --git a/spec/jobs/bulk_invoice_job_spec.rb b/spec/jobs/bulk_invoice_job_spec.rb index 130e70cfbf..63c8bf34b0 100644 --- a/spec/jobs/bulk_invoice_job_spec.rb +++ b/spec/jobs/bulk_invoice_job_spec.rb @@ -24,51 +24,29 @@ describe BulkInvoiceJob do end describe "#perform" do - let(:order1) { create(:order) } - let(:order2) { create(:order) } - let(:order3) { create(:order) } + let!(:order1) { create(:shipped_order) } + let!(:order2) { create(:order_with_line_items) } + let!(:order3) { create(:order_ready_to_ship) } let(:order_ids) { [order1.id, order2.id, order3.id] } - it "should generate invoices for invoiceable orders only" do - expect(subject).to receive(:sorted_orders).with(order_ids).and_return([order1, order2, - order3]) - expect(order1).to receive(:invoiceable?).and_return(true) - expect(order2).to receive(:invoiceable?).and_return(false) - expect(order3).to receive(:invoiceable?).and_return(true) - - [order1, order3].each do |order| - expect(subject).to receive(:generate_invoice).with(order) - end - expect(subject).not_to receive(:generate_invoice).with(order2) - - subject.perform(order_ids, "/tmp/file/path") - end - end - - describe "#generate_invoice" do - let(:order) { create(:completed_order_with_totals) } - let(:order_ids){ [order.id] } - let!(:invoice_data_generator){ InvoiceDataGenerator.new(order) } - let!(:invoice){ - create(:invoice, order:, - data: invoice_data_generator.serialize_for_invoice) - } - let(:generator){ double("generator") } - let(:renderer){ double("renderer") } - let(:printed_invoice_string){ "printed invoice string" } - + let(:path){ "/tmp/file/path.pdf" } before do - expect(OrderInvoiceGenerator).to receive(:new).with(order).and_return(generator) - expect(subject).to receive(:renderer).and_return(renderer) + order3.cancel + order3.resume end + it "should generate invoices for invoiceable orders only" do + expect{ + subject.perform(order_ids, path) + }.to change{ order1.invoices.count }.from(0).to(1) + .and change{ order2.invoices.count }.by(0) + .and change{ order3.invoices.count }.from(0).to(1) - it "should call the renderer with the invoice presenter" do - expect(generator).to receive(:generate_or_update_latest_invoice) - expect(renderer).to receive(:render_to_string).with(invoice.presenter) - .and_return(printed_invoice_string) - expect(order).to receive(:invoices).and_return([invoice]) - expect(CombinePDF).to receive(:parse).with(printed_invoice_string) - - subject.__send__(:generate_invoice, order) + File.open(path, "rb") do |io| + reader = PDF::Reader.new(io) + content = reader.pages.map(&:text).join("\n") + expect(content).to include(order1.number) + expect(content).to include(order3.number) + expect(content).not_to include(order2.number) + end end end end From 4449484402a6af328dbc41bedbea19ed734cbbe8 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Mon, 31 Jul 2023 16:18:10 +0100 Subject: [PATCH 10/12] replace double with instance_double --- spec/mailers/order_mailer_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/mailers/order_mailer_spec.rb b/spec/mailers/order_mailer_spec.rb index 5637978b16..ef19ec4ee9 100644 --- a/spec/mailers/order_mailer_spec.rb +++ b/spec/mailers/order_mailer_spec.rb @@ -226,8 +226,8 @@ describe Spree::OrderMailer do data: invoice_data_generator.serialize_for_invoice) } - let(:generator){ double(:generator) } - let(:renderer){ double(:renderer) } + let(:generator){ instance_double(OrderInvoiceGenerator) } + let(:renderer){ instance_double(InvoiceRenderer) } let(:attachment_filename){ "invoice-#{order.number}.pdf" } let(:deliveries){ ActionMailer::Base.deliveries } before do From 24b1918df5def0eff9b22f2fa60661ef0f0b5881 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Thu, 3 Aug 2023 14:05:24 +0100 Subject: [PATCH 11/12] implment blank? on Address presenter To keep the same method calls that are used on the legacy invoice template. I needed to redefine blank? on the address presenter. --- app/models/invoice/data_presenter/address.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/invoice/data_presenter/address.rb b/app/models/invoice/data_presenter/address.rb index c7a08add40..29122dceba 100644 --- a/app/models/invoice/data_presenter/address.rb +++ b/app/models/invoice/data_presenter/address.rb @@ -24,6 +24,10 @@ class Invoice render_address([address1, address2, city, zipcode, state&.name]) end + def blank? + @data.nil? + end + private def render_address(address_parts) From 9a3aef525ac303f74df672919ce923dffb145052 Mon Sep 17 00:00:00 2001 From: Mohamed ABDELLANI Date: Thu, 3 Aug 2023 14:11:22 +0100 Subject: [PATCH 12/12] add distributor's phone number to list of attributes to serialize --- app/models/invoice/data_presenter/distributor.rb | 3 ++- app/serializers/invoice/enterprise_serializer.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/models/invoice/data_presenter/distributor.rb b/app/models/invoice/data_presenter/distributor.rb index a0cc2299d3..5772ef31dd 100644 --- a/app/models/invoice/data_presenter/distributor.rb +++ b/app/models/invoice/data_presenter/distributor.rb @@ -3,7 +3,8 @@ class Invoice class DataPresenter class Distributor < Invoice::DataPresenter::Base - attributes :name, :abn, :acn, :logo_url, :display_invoice_logo, :invoice_text, :email_address + attributes :name, :abn, :acn, :logo_url, :display_invoice_logo, :invoice_text, :email_address, + :phone attributes_with_presenter :contact, :address, :business_address def display_invoice_logo? diff --git a/app/serializers/invoice/enterprise_serializer.rb b/app/serializers/invoice/enterprise_serializer.rb index 54b064fa7d..77611a75ef 100644 --- a/app/serializers/invoice/enterprise_serializer.rb +++ b/app/serializers/invoice/enterprise_serializer.rb @@ -2,7 +2,8 @@ class Invoice class EnterpriseSerializer < ActiveModel::Serializer - attributes :name, :abn, :acn, :invoice_text, :email_address, :display_invoice_logo, :logo_url + attributes :name, :abn, :acn, :invoice_text, :email_address, :display_invoice_logo, :logo_url, + :phone has_one :contact, serializer: Invoice::UserSerializer has_one :business_address, serializer: Invoice::AddressSerializer has_one :address, serializer: Invoice::AddressSerializer