diff --git a/app/mailers/standing_order_mailer.rb b/app/mailers/standing_order_mailer.rb index 050f6d7fda..8f256c1c3e 100644 --- a/app/mailers/standing_order_mailer.rb +++ b/app/mailers/standing_order_mailer.rb @@ -34,6 +34,14 @@ class StandingOrderMailer < Spree::BaseMailer :subject => "#{Spree::Config[:site_name]} #{t('standing_order_mailer.placement_summary_email.subject')}") end + def confirmation_summary_email(summary) + @shop = Enterprise.find(summary.shop_id) + @summary = summary + mail(:to => @shop.email, + :from => from_address, + :subject => "#{Spree::Config[:site_name]} #{t('standing_order_mailer.confirmation_summary_email.subject')}") + end + private def send_mail(order) diff --git a/app/views/standing_order_mailer/confirmation_summary_email.html.haml b/app/views/standing_order_mailer/confirmation_summary_email.html.haml new file mode 100644 index 0000000000..579f7d331c --- /dev/null +++ b/app/views/standing_order_mailer/confirmation_summary_email.html.haml @@ -0,0 +1,22 @@ +%table.social.white-bg{:width => "100%"} + %tr + %td + %table.column{:align => "left"} + %tr + %td + %h3 + = t(".greeting", name: @shop.contact) + %h4 + = t(".intro") + %table.column{:align => "left"} + %tr + %td{:align => "right"} + %img.float-right{:src => "#{@shop.logo.url(:medium)}"}/ + %span.clear + += render 'summary_overview', summary: @summary += render 'summary_detail', summary: @summary + +%p   += render 'shared/mailers/signoff' += render 'shared/mailers/social_and_contact' diff --git a/config/locales/en.yml b/config/locales/en.yml index d60ca211db..43ac0a2bdd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -109,11 +109,15 @@ en: subject: "Order cycle report for %{producer}" standing_order_mailer: placement_summary_email: - subject: Your Standing Order summary + subject: A summary of recently placed standing orders greeting: "Hi %{name}," intro: "Below is a summary of the standing orders that have just been placed for %{shop}." + confirmation_summary_email: + subject: A summary of recently confirmed standing orders + greeting: "Hi %{name}," + intro: "Below is a summary of the standing orders that have just been finalised for %{shop}." summary_overview: - total: A total of %{count} standing orders were marked for automatic placement. + total: A total of %{count} standing orders were marked for automatic processing. success_zero: Of these, none were processed successfully. success_some: Of these, %{count} were processed successfully. success_all: All were processed successfully. @@ -132,6 +136,9 @@ en: processing: title: Error Encountered (%{count} orders) explainer: Automatic processing of these orders failed due to an error. The error has been listed where possible. + failed_payment: + title: Failed Payment (%{count} orders) + explainer: Automatic processing of payment for these orders failed due to an error. The error has been listed where possible. other: title: Other Failure (%{count} orders) explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. diff --git a/spec/mailers/standing_order_mailer_spec.rb b/spec/mailers/standing_order_mailer_spec.rb index 7f7b92908a..18c6b9a225 100644 --- a/spec/mailers/standing_order_mailer_spec.rb +++ b/spec/mailers/standing_order_mailer_spec.rb @@ -213,4 +213,114 @@ describe StandingOrderMailer do end end end + + describe "order confirmation summary" do + let!(:shop) { create(:enterprise) } + let!(:summary) { double(:summary, shop_id: shop.id) } + let(:body) { strip_tags(StandingOrderMailer.deliveries.last.body.encoded) } + let(:scope) { "standing_order_mailer" } + + before { allow(summary).to receive(:unrecorded_ids) { [] } } + + context "when no issues were encountered while processing standing orders" do + before do + allow(summary).to receive(:order_count) { 37 } + allow(summary).to receive(:issue_count) { 0 } + allow(summary).to receive(:issues) { {} } + StandingOrderMailer.confirmation_summary_email(summary).deliver + end + + it "sends the email, which notifies the enterprise that all orders were successfully processed" do + expect(body).to include I18n.t("#{scope}.confirmation_summary_email.intro") + expect(body).to include I18n.t("#{scope}.summary_overview.total", count: 37) + expect(body).to include I18n.t("#{scope}.summary_overview.success_all") + expect(body).to_not include I18n.t("#{scope}.summary_overview.issues") + end + end + + context "when some issues were encountered while processing standing orders" do + let(:order1) { double(:order, id: 1, number: "R123456", to_s: "R123456") } + let(:order2) { double(:order, id: 2, number: "R654321", to_s: "R654321") } + + before do + allow(summary).to receive(:order_count) { 37 } + allow(summary).to receive(:success_count) { 35 } + allow(summary).to receive(:issue_count) { 2 } + allow(summary).to receive(:issues) { { failed_payment: { 1 => "Some Error Message", 2 => nil } } } + allow(summary).to receive(:orders_affected_by) { [order1, order2] } + end + + context "when no unrecorded issues are present" do + it "sends the email, which notifies the enterprise that some issues were encountered" do + StandingOrderMailer.confirmation_summary_email(summary).deliver + expect(body).to include I18n.t("#{scope}.confirmation_summary_email.intro") + expect(body).to include I18n.t("#{scope}.summary_overview.total", count: 37) + expect(body).to include I18n.t("#{scope}.summary_overview.success_some", count: 35) + expect(body).to include I18n.t("#{scope}.summary_overview.issues") + expect(body).to include I18n.t("#{scope}.summary_detail.failed_payment.title", count: 2) + expect(body).to include I18n.t("#{scope}.summary_detail.failed_payment.explainer") + + # Lists orders for which an error was encountered + expect(body).to include order1.number + expect(body).to include order2.number + + # Reports error messages provided by the summary, or default if none provided + expect(body).to include "Some Error Message" + expect(body).to include I18n.t("#{scope}.summary_detail.no_message_provided") + end + end + + context "when some undocumented orders are present" do + let(:order3) { double(:order, id: 3, number: "R333333", to_s: "R333333") } + let(:order4) { double(:order, id: 4, number: "R444444", to_s: "R444444") } + + before do + allow(summary).to receive(:unrecorded_ids) { [3, 4] } + end + + it "sends the email, which notifies the enterprise that some issues were encountered" do + expect(summary).to receive(:orders_affected_by).with(:other) { [order3, order4] } + StandingOrderMailer.confirmation_summary_email(summary).deliver + expect(body).to include I18n.t("#{scope}.summary_detail.failed_payment.title", count: 2) + expect(body).to include I18n.t("#{scope}.summary_detail.failed_payment.explainer") + expect(body).to include I18n.t("#{scope}.summary_detail.other.title", count: 2) + expect(body).to include I18n.t("#{scope}.summary_detail.other.explainer") + + # Lists orders for which no error or success was recorded + expect(body).to include order3.number + expect(body).to include order4.number + end + end + end + + context "when no standing orders were processed successfully" do + let(:order1) { double(:order, id: 1, number: "R123456", to_s: "R123456") } + let(:order2) { double(:order, id: 2, number: "R654321", to_s: "R654321") } + + before do + allow(summary).to receive(:order_count) { 2 } + allow(summary).to receive(:success_count) { 0 } + allow(summary).to receive(:issue_count) { 2 } + allow(summary).to receive(:issues) { { changes: { 1 => nil, 2 => nil } } } + allow(summary).to receive(:orders_affected_by) { [order1, order2] } + StandingOrderMailer.confirmation_summary_email(summary).deliver + end + + it "sends the email, which notifies the enterprise that some issues were encountered" do + expect(body).to include I18n.t("#{scope}.confirmation_summary_email.intro") + expect(body).to include I18n.t("#{scope}.summary_overview.total", count: 2) + expect(body).to include I18n.t("#{scope}.summary_overview.success_zero") + expect(body).to include I18n.t("#{scope}.summary_overview.issues") + expect(body).to include I18n.t("#{scope}.summary_detail.changes.title", count: 2) + expect(body).to include I18n.t("#{scope}.summary_detail.changes.explainer") + + # Lists orders for which an error was encountered + expect(body).to include order1.number + expect(body).to include order2.number + + # No error messages reported when non provided + expect(body).to_not include I18n.t("#{scope}.summary_detail.no_message_provided") + end + end + end end