When an order is cancelled by a customer send an email to the shop.

Fixes #6435 i.e. If the customer paid for their order by Stripe/Paypal then the Enterprise needs to know that the order was cancelled in order to arrange a refund.  Refunds are not automatically processed when an order is cancelled.

This will send a very basic email to the shop, it only includes a link to view the cancelled order in the admin area initially.

I created a CustomerOrderCancellation object here because orders can be cancelled in two ways (1) by the customer, so an email should be sent to the shop. (2) by the shop, so an email doesn't need to be sent. However the code for cancelling order happens in Order#cancel via the state machine. Rather than passing some sort of parameter into #cancel to indicate whether it is a customer or shop cancelled order it might be clearer to have a CustomerOrderCancellation object, there could be other differences between customer or shop cancelled orders in future maybe.
This commit is contained in:
Cillian O'Ruanaidh
2021-01-22 14:42:41 +00:00
parent 818dfc0399
commit 899dffec96
7 changed files with 86 additions and 1 deletions

View File

@@ -136,7 +136,7 @@ module Spree
@order = Spree::Order.find_by!(number: params[:id])
authorize! :cancel, @order
if @order.cancel
if CustomerOrderCancellation.new(@order).call
flash[:success] = I18n.t(:orders_your_order_has_been_cancelled)
else
flash[:error] = I18n.t(:orders_could_not_cancel)

View File

@@ -17,6 +17,16 @@ module Spree
end
end
def cancel_email_for_shop(order)
@order = order
I18n.with_locale valid_locale(@order.distributor.owner) do
subject = I18n.t('spree.order_mailer.cancel_email_for_shop.subject')
mail(to: @order.distributor.contact.email,
from: from_address,
subject: subject)
end
end
def confirm_email_for_customer(order_or_order_id, resend = false)
@order = find_order(order_or_order_id)
I18n.with_locale valid_locale(@order.user) do

View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
class CustomerOrderCancellation
def initialize(order)
@order = order
end
def call
return unless order.cancel
Spree::OrderMailer.cancel_email_for_shop(order).deliver_later
end
private
attr_reader :order
end

View File

@@ -0,0 +1,7 @@
%p
= t('spree.order_mailer.cancel_email_for_shop.greeting', name: @order.distributor.name)
%p
= t('spree.order_mailer.cancel_email_for_shop.intro', number: @order.number)
= link_to t('spree.order_mailer.cancel_email_for_shop.view_cancelled_order'), spree.admin_order_url(@order)

View File

@@ -3631,6 +3631,11 @@ See the %{link} to find out more about %{sitename}'s features and to start using
paid_order: "Your order was paid so %{distributor} has refunded the full amount"
credit_order: "Your order was paid so your account has been credited"
subject: "Cancellation of Order"
cancel_email_for_shop:
greeting: "Dear %{name},"
subject: "Cancellation of Order"
intro: "A customer has cancelled their order #%{number}."
view_cancelled_order: "View cancelled order"
confirm_email:
subject: "Order Confirmation"
invoice_email:

View File

@@ -77,6 +77,21 @@ describe Spree::OrderMailer do
end
end
describe "#cancel_email_for_shop" do
let(:distributor) { create(:distributor_enterprise) }
let(:order) { create(:order, distributor: distributor, state: "canceled") }
let(:admin_order_link_href) { "href=\"#{spree.admin_order_url(order)}\"" }
let(:mail) { Spree::OrderMailer.cancel_email_for_shop(order) }
it "sends an email to the distributor" do
expect(mail.to).to eq([distributor.contact.email])
end
it "includes a link to the cancelled order in admin" do
expect(mail.body).to match /#{admin_order_link_href}/
end
end
describe "order confimation" do
let(:bill_address) { create(:address) }
let(:distributor_address) { create(:address, address1: "distributor address", city: 'The Shire', zipcode: "1234") }

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
describe CustomerOrderCancellation do
let(:mail_mock) { double(:mailer_mock, deliver_later: true) }
before do
allow(Spree::OrderMailer).to receive(:cancel_email_for_shop) { mail_mock }
end
context "when an order is cancelled successfully" do
it "notifies the distributor by email" do
order = create(:order, completed_at: Time.now, state: 'complete')
CustomerOrderCancellation.new(order).call
expect(Spree::OrderMailer).to have_received(:cancel_email_for_shop).with(order)
expect(mail_mock).to have_received(:deliver_later)
end
end
context "when the order fails to cancel" do
it "doesn't notify the distributor by email" do
order = create(:order, state: 'canceled')
CustomerOrderCancellation.new(order).call
expect(Spree::OrderMailer).to_not have_received(:cancel_email_for_shop)
end
end
end