spree_emails 6.0.0.beta2 → 6.0.0.beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cfd401a89825dc6638e8fb859dea1153ccb105d9338422bfd31f38c33b620bc
4
- data.tar.gz: 803a387e672ea1ea39a878b180048e6714ae15b0077fa87cfc0821e8d654a8dd
3
+ metadata.gz: 4e39192d17144a4963b3c0fb926d656cc639f165927b8fa78956aa230c58bfc6
4
+ data.tar.gz: '0878e0210c83640d6c35b063c2e7dc89f427a6e58f178838b562dadc8bd2ac20'
5
5
  SHA512:
6
- metadata.gz: 5a0267600233c8d924c4bd4dda0be05854d04c35b4962b44d6e5e002ea5e1678fc7d01631de306cce52d05cb77236f3cde0673895f10f353b7af463f03ee0d56
7
- data.tar.gz: 269b7edd362f3d124deb9288abe348927fe6580ef54b5fbe9bd200890ee1724712e91a94abd100620fb88f97d7f5c25e5f1b77dccfee931f6ea45b880e523028
6
+ metadata.gz: 24d2af93481b95787c95ff9b442b7a723e1564fbecf89cf87b61320cd9240f172111b0be599ab12f1d334df99594702af1ee7ab405ab02ae6f2a438f31103546
7
+ data.tar.gz: c686e22de2d14aa715ee81593c649333fff0c2f2bfdf45336fd0b3a6e125244be88cbc892e168f130156baefdb8dec06bf4fe382d5ae8e93b9ba45901c530f73
@@ -0,0 +1,51 @@
1
+ module Spree
2
+ # The purchase a customer made, when it produced more than one order.
3
+ #
4
+ # A checkout spanning several sellers divides into one order per seller, and
5
+ # no one of them is the purchase — each holds a single seller's items,
6
+ # delivery and total. So the confirmation is sent from the group: one email
7
+ # naming the number the customer saw at checkout, every item they bought, the
8
+ # total they actually paid, and the parcels it will arrive in.
9
+ #
10
+ # Kept separate from +Spree::OrderMailer+ rather than folded into it: a
11
+ # checkout that does not split is still one order and still sends that
12
+ # email unchanged, and a storefront replacing one document should not have to
13
+ # inherit the other.
14
+ class OrderGroupMailer < BaseMailer
15
+ helper Spree::MailHelper
16
+
17
+ # @param order_group [Spree::OrderGroup, Integer, String] record or id
18
+ # @param resend [Boolean] prefixes the subject, for an admin re-send
19
+ def confirm_email(order_group, resend = false)
20
+ @order_group = find_order_group(order_group)
21
+ # Assigned rather than left to BaseMailer#current_store, which memoizes
22
+ # off @order and would otherwise fall back to the default store — the
23
+ # wrong store's name, logo and footer on a multi-store install.
24
+ @current_store = @order_group.store
25
+
26
+ with_store_locale(@current_store, @order_group.locale) do
27
+ subject = order_email_subject(
28
+ @current_store, Spree.t('order_group_mailer.confirm_email.subject'), @order_group.number, resend: resend
29
+ )
30
+ mail(to: @order_group.email, subject: subject, store_url: @current_store.storefront_url)
31
+ end
32
+ end
33
+
34
+ def store_owner_notification_email(order_group)
35
+ @order_group = find_order_group(order_group)
36
+ @current_store = @order_group.store
37
+
38
+ with_store_locale(@current_store) do
39
+ subject = Spree.t('order_group_mailer.store_owner_notification_email.subject', store_name: @current_store.name)
40
+ mail(to: @current_store.new_order_notifications_email, subject: subject,
41
+ store_url: @current_store.storefront_url)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def find_order_group(order_group)
48
+ order_group.respond_to?(:id) ? order_group : Spree::OrderGroup.find(order_group)
49
+ end
50
+ end
51
+ end
@@ -13,26 +13,33 @@ module Spree
13
13
  def send_confirmation_email(event)
14
14
  order = find_order(event)
15
15
  return unless order
16
+
17
+ send_customer_confirmation(order, event)
18
+ send_store_owner_notification(order)
19
+ end
20
+
21
+ def send_customer_confirmation(order, event)
16
22
  return if order.confirmation_delivered?
17
23
  return if event.payload['notify_customer'] == false
18
-
19
- store = order.store
20
- return unless store.prefers_send_consumer_transactional_emails?
24
+ return unless order.store.prefers_send_consumer_transactional_emails?
21
25
 
22
26
  OrderMailer.confirm_email(order.id).deliver_later
23
27
  order.update_column(:confirmation_delivered, true)
24
-
25
- send_store_owner_notification(order) if should_notify_store_owner?(order)
26
28
  end
27
29
 
30
+ # An admin resends from an order, because an order is what they are looking
31
+ # at. On a split checkout the document to send is still the purchase's —
32
+ # sending this child's would put back the partial confirmation the group
33
+ # email exists to replace.
28
34
  def resend_confirmation_email(event)
29
35
  order = find_order(event)
30
36
  return unless order
37
+ return order.order_group.publish_event('order_group.resend_confirmation_email') if order.grouped?
31
38
 
32
39
  store = order.store
33
40
  return unless store.prefers_send_consumer_transactional_emails?
34
41
 
35
- OrderMailer.confirm_email(order.id).deliver_later
42
+ OrderMailer.confirm_email(order.id, true).deliver_later
36
43
  order.update_column(:confirmation_delivered, true)
37
44
  end
38
45
 
@@ -48,6 +55,9 @@ module Spree
48
55
  end
49
56
 
50
57
  def send_store_owner_notification(order)
58
+ # A divided checkout tells the store about the purchase once, from the
59
+ # group, rather than once per seller order.
60
+ return if order.grouped?
51
61
  return if order.store_owner_notification_delivered?
52
62
  return if order.store.new_order_notifications_email.blank?
53
63
 
@@ -55,11 +65,6 @@ module Spree
55
65
  order.update_column(:store_owner_notification_delivered, true)
56
66
  end
57
67
 
58
- def should_notify_store_owner?(order)
59
- order.store.new_order_notifications_email.present? &&
60
- !order.store_owner_notification_delivered?
61
- end
62
-
63
68
  def find_order(event)
64
69
  order_id = event.payload['id']
65
70
  Spree::Order.find_by_prefix_id(order_id)
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ # The confirmation for a checkout that produced more than one order.
5
+ #
6
+ # Its child orders place silently (+Spree::Carts::Complete#complete_orders+),
7
+ # because none of them is the purchase — this is what tells the customer what
8
+ # they bought, what they paid and how it arrives.
9
+ class OrderGroupEmailSubscriber < Spree::Subscriber
10
+ subscribes_to 'order_group.completed', 'order_group.resend_confirmation_email'
11
+
12
+ on 'order_group.completed', :send_confirmation_email
13
+ on 'order_group.resend_confirmation_email', :resend_confirmation_email
14
+
15
+ private
16
+
17
+ def send_confirmation_email(event)
18
+ order_group = find_order_group(event)
19
+ return unless order_group
20
+
21
+ send_customer_confirmation(order_group, event)
22
+ send_store_owner_notification(order_group)
23
+ end
24
+
25
+ # The operator is a different audience: silencing the customer, or turning
26
+ # their receipts off, says nothing about whether the store wants to hear
27
+ # about the sale.
28
+ def send_customer_confirmation(order_group, event)
29
+ return if order_group.confirmation_delivered?
30
+ return if event.payload['notify_customer'] == false
31
+ return unless order_group.store.prefers_send_consumer_transactional_emails?
32
+
33
+ OrderGroupMailer.confirm_email(order_group.id).deliver_later
34
+ order_group.update_column(:confirmation_delivered, true)
35
+ end
36
+
37
+ def resend_confirmation_email(event)
38
+ order_group = find_order_group(event)
39
+ return unless order_group
40
+ return unless order_group.store.prefers_send_consumer_transactional_emails?
41
+
42
+ OrderGroupMailer.confirm_email(order_group.id, true).deliver_later
43
+ order_group.update_column(:confirmation_delivered, true)
44
+ end
45
+
46
+ # One notification per purchase, like the customer's. Told about the
47
+ # checkout rather than about each seller's share of it, because that is
48
+ # what happened.
49
+ def send_store_owner_notification(order_group)
50
+ return if order_group.store_owner_notification_delivered?
51
+ return if order_group.store.new_order_notifications_email.blank?
52
+
53
+ OrderGroupMailer.store_owner_notification_email(order_group.id).deliver_later
54
+ order_group.update_column(:store_owner_notification_delivered, true)
55
+ end
56
+
57
+ def find_order_group(event)
58
+ Spree::OrderGroup.find_by_prefix_id(event.payload['id'])
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,38 @@
1
+ <%= render 'spree/shared/purchased_items_styles' %>
2
+
3
+ <% fulfillment_groups = @order_group.fulfillment_groups %>
4
+ <% unfulfilled_line_items = @order_group.unfulfilled_line_items(fulfillment_groups) %>
5
+
6
+ <%= render layout: 'spree/shared/mailer_hero' do %>
7
+ <h1><%= Spree.t('order_group_mailer.confirm_email.subject') %></h1>
8
+ <p class="greeting"><%= Spree.t('order_group_mailer.confirm_email.dear_customer', name: name_for(@order_group)) %></p>
9
+ <p><%= Spree.t('order_group_mailer.confirm_email.instructions', number: @order_group.number) %></p>
10
+ <%# What the customer most needs and least expects: this arrives in more
11
+ than one delivery. Counted from the parcels, never from the orders the
12
+ checkout divided into — several sellers shipping out of one warehouse
13
+ send one box. %>
14
+ <% if fulfillment_groups.many? %>
15
+ <p><%= Spree.t('order_group_mailer.confirm_email.arriving_separately', count: fulfillment_groups.size) %></p>
16
+ <% end %>
17
+ <% end %>
18
+
19
+ <% if @order_group.po_number.present? %>
20
+ <p class="f-fallback"><%= Spree.t('order_mailer.po_number', number: @order_group.po_number) %></p>
21
+ <% end %>
22
+
23
+ <% fulfillment_groups.each_with_index do |fulfillment_group, index| %>
24
+ <%= render 'spree/shared/fulfillment_group_section',
25
+ fulfillment_group: fulfillment_group,
26
+ position: index + 1,
27
+ count: fulfillment_groups.size %>
28
+ <% end %>
29
+
30
+ <% if unfulfilled_line_items.any? %>
31
+ <%= render 'spree/shared/order_summary_section',
32
+ heading: Spree.t('order_group_mailer.nothing_to_ship'),
33
+ line_items: unfulfilled_line_items,
34
+ order: @order_group,
35
+ totals: false %>
36
+ <% end %>
37
+
38
+ <%= render 'spree/shared/purchase_totals', order_group: @order_group %>
@@ -0,0 +1,26 @@
1
+ <% fulfillment_groups = @order_group.fulfillment_groups %>
2
+ <% unfulfilled_line_items = @order_group.unfulfilled_line_items(fulfillment_groups) %>
3
+ <%= Spree.t('order_group_mailer.confirm_email.dear_customer', name: name_for(@order_group)) %>
4
+
5
+ <%= Spree.t('order_group_mailer.confirm_email.instructions', number: @order_group.number) %>
6
+ <% if fulfillment_groups.many? %>
7
+ <%= Spree.t('order_group_mailer.confirm_email.arriving_separately', count: fulfillment_groups.size) %>
8
+ <% end %>
9
+ <%= render 'spree/shared/po_number', order: @order_group %>
10
+ <% fulfillment_groups.each_with_index do |fulfillment_group, index| %>
11
+ ============================================================
12
+ <%= render 'spree/shared/fulfillment_group_section',
13
+ fulfillment_group: fulfillment_group,
14
+ position: index + 1,
15
+ count: fulfillment_groups.size %>
16
+ <% end %>
17
+ <% if unfulfilled_line_items.any? %>
18
+ ============================================================
19
+ <%= Spree.t('order_group_mailer.nothing_to_ship') %>
20
+ <% unfulfilled_line_items.each do |item| %>
21
+ <%= item.variant.sku %> <%= item.variant.product.name %> <%= item.variant.options_text -%> (<%= item.quantity %>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %>
22
+ <% end %>
23
+ <% end %>
24
+ <%= render 'spree/shared/purchase_totals', order_group: @order_group %>
25
+ <%= Spree.t('order_group_mailer.confirm_email.thanks') %>
26
+ <%= Spree.t('order_mailer.store_team', store_name: current_store.name) %>
@@ -0,0 +1,14 @@
1
+ <%= render 'spree/shared/purchased_items_styles' %>
2
+
3
+ <%= render layout: 'spree/shared/mailer_hero' do %>
4
+ <h1><%= Spree.t('order_group_mailer.store_owner_notification_email.heading') %></h1>
5
+ <p><%= Spree.t('order_group_mailer.store_owner_notification_email.instructions', count: @order_group.orders.size) %></p>
6
+ <% end %>
7
+
8
+ <%= render 'spree/shared/order_summary_section',
9
+ heading: Spree.t('order_group_mailer.store_owner_notification_email.purchase_summary', number: @order_group.number),
10
+ line_items: @order_group.line_items,
11
+ order: @order_group,
12
+ totals: false %>
13
+
14
+ <%= render 'spree/shared/purchase_totals', order_group: @order_group %>
@@ -0,0 +1,11 @@
1
+ <%= Spree.t('order_group_mailer.store_owner_notification_email.instructions', count: @order_group.orders.size) %>
2
+
3
+ ============================================================
4
+ <%= Spree.t('order_group_mailer.store_owner_notification_email.purchase_summary', number: @order_group.number) %>
5
+ ============================================================
6
+ <%= render 'spree/shared/po_number', order: @order_group %>
7
+ <% @order_group.line_items.each do |item| %>
8
+ <%= item.variant.sku %> <%= item.variant.product.name %> <%= item.variant.options_text -%> (<%= item.quantity %>) <%= Spree.t('at_symbol') %> <%= item.single_money %> = <%= item.display_amount %>
9
+ <% end %>
10
+ <%= render 'spree/shared/purchase_totals', order_group: @order_group %>
11
+ <%= Spree.t('order_mailer.store_team', store_name: current_store.name) %>
@@ -0,0 +1,37 @@
1
+ <%# One real parcel of a purchase, with the goods it carries and what it cost
2
+ to deliver. Locals: fulfillment_group, position, count.
3
+
4
+ A purchase arriving in one parcel is not numbered — "Delivery 1 of 1"
5
+ tells the customer nothing they did not already assume.
6
+
7
+ Rendered from the parcel's manifest rather than its line items: a line
8
+ packed from two warehouses travels in two parcels, and its own quantity
9
+ describes the whole order rather than this box. %>
10
+ <table class="section" width="100%" cellpadding="0" cellspacing="0" role="presentation">
11
+ <tr>
12
+ <td>
13
+ <h3 class="f-fallback">
14
+ <% if count > 1 %>
15
+ <%= Spree.t('order_group_mailer.delivery_numbered', position: position, count: count) %>
16
+ <% else %>
17
+ <%= Spree.t('order_group_mailer.delivery') %>
18
+ <% end %>
19
+ </h3>
20
+ <% if fulfillment_group.sellers.any? %>
21
+ <p class="f-fallback sub"><%= Spree.t('order_group_mailer.sold_by', sellers: fulfillment_group.sellers.map(&:name).to_sentence) %></p>
22
+ <% end %>
23
+ <% fulfillment_group.manifest.each do |item| %>
24
+ <%= render 'spree/shared/purchased_items_table/line_item',
25
+ line_item: item.line_item,
26
+ quantity: item.quantity,
27
+ amount: Spree::Money.new(item.line_item.price * item.quantity, currency: item.line_item.currency) %>
28
+ <% end %>
29
+ <table class="summary purchase_content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
30
+ <%= render 'spree/shared/purchased_items_table/summary_row',
31
+ label: Spree.t(:shipping),
32
+ sub: fulfillment_group.name,
33
+ value: fulfillment_group.display_cost %>
34
+ </table>
35
+ </td>
36
+ </tr>
37
+ </table>
@@ -0,0 +1,12 @@
1
+ <% if count > 1 %>
2
+ <%= Spree.t('order_group_mailer.delivery_numbered', position: position, count: count) %>
3
+ <% else %>
4
+ <%= Spree.t('order_group_mailer.delivery') %>
5
+ <% end %>
6
+ <% if fulfillment_group.sellers.any? %>
7
+ <%= Spree.t('order_group_mailer.sold_by', sellers: fulfillment_group.sellers.map(&:name).to_sentence) %>
8
+ <% end %>
9
+ <% fulfillment_group.manifest.each do |item| %>
10
+ <%= item.variant.sku %> <%= item.variant.product.name %> <%= item.variant.options_text -%> (<%= item.quantity %>) <%= Spree.t('at_symbol') %> <%= item.line_item.single_money %> = <%= Spree::Money.new(item.line_item.price * item.quantity, currency: item.line_item.currency) %>
11
+ <% end %>
12
+ <%= Spree.t(:shipping) %>: <%= fulfillment_group.name %> <%= fulfillment_group.display_cost %>
@@ -0,0 +1,62 @@
1
+ <%# Every figure of the whole purchase, once. Locals: order_group.
2
+
3
+ Deliberately not the order summary's own totals block: that one reaches
4
+ into one order's fulfillments and money rows, and a purchase has neither
5
+ of its own. These read the group's roll-up of what each child independently
6
+ computed. Delivery is one line here and broken down per parcel above. %>
7
+ <table class="section" width="100%" cellpadding="0" cellspacing="0" role="presentation">
8
+ <tr>
9
+ <td>
10
+ <h3 class="f-fallback"><%= Spree.t(:order_summary) %></h3>
11
+ <table class="summary purchase_content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
12
+ <%= render 'spree/shared/purchased_items_table/summary_row',
13
+ label: Spree.t('order_mailer.subtotal'),
14
+ value: order_group.display_item_total %>
15
+
16
+ <% order_group.discounts.promotion.to_a.group_by(&:label).each do |label, discounts| %>
17
+ <%= render 'spree/shared/purchased_items_table/summary_row',
18
+ label: Spree.t(:promotion),
19
+ sub: label,
20
+ value: Spree::Money.new(discounts.sum(&:amount), currency: order_group.currency) %>
21
+ <% end %>
22
+
23
+ <% if order_group.delivery_total != 0 %>
24
+ <%= render 'spree/shared/purchased_items_table/summary_row',
25
+ label: Spree.t(:shipping),
26
+ value: order_group.display_delivery_total %>
27
+ <% end %>
28
+
29
+ <% if order_group.additional_tax_total != 0 %>
30
+ <%= render 'spree/shared/purchased_items_table/summary_row',
31
+ label: Spree.t(:tax),
32
+ value: order_group.display_additional_tax_total %>
33
+ <% end %>
34
+
35
+ <% if order_group.gift_card_total.positive? %>
36
+ <%= render 'spree/shared/purchased_items_table/summary_row',
37
+ label: Spree.t(:gift_card),
38
+ value: safe_join(['-', order_group.display_gift_card_total.to_html]) %>
39
+ <% end %>
40
+
41
+ <% order_group.discounts.manual.to_a.group_by(&:label).each do |label, discounts| %>
42
+ <%= render 'spree/shared/purchased_items_table/summary_row',
43
+ label: label,
44
+ value: Spree::Money.new(discounts.sum(&:amount), currency: order_group.currency) %>
45
+ <% end %>
46
+
47
+ <% order_group.fees.to_a.group_by(&:label).each do |label, fees| %>
48
+ <% amount = fees.sum(&:amount) %>
49
+ <% next if amount.zero? %>
50
+ <%= render 'spree/shared/purchased_items_table/summary_row',
51
+ label: label,
52
+ value: Spree::Money.new(amount, currency: order_group.currency) %>
53
+ <% end %>
54
+
55
+ <%= render 'spree/shared/purchased_items_table/summary_row',
56
+ row_class: 'summary_total',
57
+ label: Spree.t('order_mailer.total'),
58
+ value: order_group.display_total_minus_store_credits %>
59
+ </table>
60
+ </td>
61
+ </tr>
62
+ </table>
@@ -0,0 +1,24 @@
1
+ ============================================================
2
+ <%= Spree.t('order_mailer.subtotal') %> <%= order_group.display_item_total %>
3
+ <% order_group.discounts.promotion.to_a.group_by(&:label).each do |label, discounts| %>
4
+ <%= Spree.t(:promotion) %>: <%= label %> <%= Spree::Money.new(discounts.sum(&:amount), currency: order_group.currency) %>
5
+ <% end %>
6
+ <% if order_group.delivery_total != 0 %>
7
+ <%= Spree.t(:shipping) %>: <%= order_group.display_delivery_total %>
8
+ <% end %>
9
+ <% if order_group.additional_tax_total != 0 %>
10
+ <%= Spree.t(:tax) %>: <%= order_group.display_additional_tax_total %>
11
+ <% end %>
12
+ <% if order_group.gift_card_total.positive? %>
13
+ <%= Spree.t(:gift_card) %>: -<%= order_group.display_gift_card_total %>
14
+ <% end %>
15
+ <% order_group.discounts.manual.to_a.group_by(&:label).each do |label, discounts| %>
16
+ <%= label %> <%= Spree::Money.new(discounts.sum(&:amount), currency: order_group.currency) %>
17
+ <% end %>
18
+ <% order_group.fees.to_a.group_by(&:label).each do |label, fees| %>
19
+ <% amount = fees.sum(&:amount) %>
20
+ <% next if amount.zero? %>
21
+ <%= label %> <%= Spree::Money.new(amount, currency: order_group.currency) %>
22
+ <% end %>
23
+ ============================================================
24
+ <%= Spree.t('order_mailer.total') %> <%= order_group.display_total_minus_store_credits %>
@@ -13,7 +13,7 @@
13
13
  <%= render 'spree/shared/purchased_items_table/summary_row',
14
14
  label: Spree.t(:shipping),
15
15
  sub: name,
16
- value: Spree::Money.new(shipments.sum(&:discounted_cost), currency: order.currency) %>
16
+ value: Spree::Money.new(shipments.sum(&:cost), currency: order.currency) %>
17
17
  <% end %>
18
18
  <% if order.additional_tax_total != 0 %>
19
19
  <%= render 'spree/shared/purchased_items_table/summary_row',
@@ -8,7 +8,7 @@
8
8
  <% end %>
9
9
 
10
10
  <% order.fulfillments.group_by { |f| f.selected_delivery_rate.try(:name) }.each do |name, shipments| %>
11
- <%= Spree.t(:shipping) %>: <%= name %> <%= Spree::Money.new(shipments.sum(&:discounted_cost), currency: order.currency) %>
11
+ <%= Spree.t(:shipping) %>: <%= name %> <%= Spree::Money.new(shipments.sum(&:cost), currency: order.currency) %>
12
12
  <% end %>
13
13
 
14
14
  <% if order.additional_tax_total != 0 %>
@@ -1,3 +1,8 @@
1
+ <%# One purchased line. Locals: line_item, and optionally quantity + amount
2
+ for a view showing part of a line — a parcel carrying two of the three
3
+ ordered, say — where the line's own figures describe more than is there. %>
4
+ <% quantity = local_assigns.fetch(:quantity, line_item.quantity) %>
5
+ <% amount = local_assigns.fetch(:amount, line_item.display_amount) %>
1
6
  <table class="item" width="100%" cellpadding="0" cellspacing="0" role="presentation">
2
7
  <tr>
3
8
  <td class="item_image" width="96" valign="middle">
@@ -12,8 +17,8 @@
12
17
  <% end %>
13
18
  </td>
14
19
  <td class="item_amount" align="right" valign="middle">
15
- <p class="item_qty f-fallback"><%= line_item.quantity %> x <%= line_item.single_money %></p>
16
- <p class="item_price f-fallback"><%= line_item.display_amount %></p>
20
+ <p class="item_qty f-fallback"><%= quantity %> x <%= line_item.single_money %></p>
21
+ <p class="item_price f-fallback"><%= amount %></p>
17
22
  </td>
18
23
  </tr>
19
24
  </table>
@@ -0,0 +1,22 @@
1
+ base_locale: en
2
+
3
+ data:
4
+ yaml:
5
+ write:
6
+ # do not wrap lines at 80 characters
7
+ line_width: -1
8
+
9
+ # Core's keys are read but never written here: the mailers and their
10
+ # templates share the vocabulary every Spree surface uses (shipping, tax,
11
+ # promotion) and only own the copy of the emails themselves.
12
+ external:
13
+ - "<%= File.expand_path('../core/config/locales', Dir.pwd) %>/%{locale}.yml"
14
+
15
+ # Find translate calls
16
+ search:
17
+ paths:
18
+ - 'app'
19
+ - 'lib'
20
+
21
+ # The PatternMapper for Spree.t
22
+ <% I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper', patterns: [['\bSpree\.t[( ]\s*%{key}', 'spree.%{key}']] %>
@@ -0,0 +1,141 @@
1
+ ---
2
+ en:
3
+ spree:
4
+ company_mailer:
5
+ invitation_email:
6
+ action: Accept invitation
7
+ expiry_notice: This invitation link will expire in 30 days.
8
+ greeting: Hi,
9
+ ignore_notice: If you were not expecting this invitation, you can safely ignore this email.
10
+ instructions: You have been invited to join %{company} on %{store}. Accept the invitation to start purchasing on the company's behalf.
11
+ subject: invitation to join %{company}
12
+ title: Join %{company}
13
+ customer_mailer:
14
+ data_export_email:
15
+ action: Download Your Data
16
+ expiry_notice: This download link expires on %{date}.
17
+ greeting: Hello,
18
+ ignore_notice: If you did not request a copy of your data, please contact us.
19
+ instructions: Your copy of the personal data we hold about you is ready. Use the button below to download it.
20
+ subject: Your Data Is Ready to Download
21
+ password_reset_email:
22
+ action: Reset Password
23
+ expiry_notice: This password reset link will expire shortly. If you did not request this, no action is needed.
24
+ greeting: Hi %{name},
25
+ ignore_notice: If you did not request a password reset, you can safely ignore this email. Your password will not be changed.
26
+ instructions: We received a request to reset your password. Click the button below to choose a new password.
27
+ subject: Password Reset Instructions
28
+ digital_asset_mailer:
29
+ files_ready_email:
30
+ available_until: Available until %{date}
31
+ dear_customer: Dear %{name},
32
+ instructions: The files from your order %{number} are ready to download.
33
+ store_team: "%{store_name} Team"
34
+ subject: Your files are ready
35
+ thanks: Thank you for your business.
36
+ fulfillment_mailer:
37
+ fulfilled_email:
38
+ dear_customer: Dear %{name},
39
+ delivery_method: 'Delivery method: %{delivery_method}'
40
+ fulfillment_summary: Fulfillment summary for order
41
+ instructions: Your order %{number} has been fulfilled
42
+ store_team: "%{store_name} Team"
43
+ subject: Fulfillment Notification
44
+ thanks: Thank you for your business.
45
+ track_information: 'Tracking Information: %{tracking}'
46
+ track_link: 'Tracking Link: %{url}'
47
+ newsletter_mailer:
48
+ email_confirmation:
49
+ dear_customer: Hey,
50
+ ignore_disclaimer: If you didn't request this, please ignore this email.
51
+ instructions: Please click the button below to verify your email address.
52
+ message_copy_link: 'If the button doesn''t work please copy and paste the following link to your browser:'
53
+ store_team: "%{store_name} Team"
54
+ subject: Verify your email address
55
+ thanks: Thank you
56
+ verify_email_address_link: Verify email address
57
+ order_group_mailer:
58
+ confirm_email:
59
+ arriving_separately:
60
+ one: Your order is arriving in one delivery.
61
+ other: Your order is arriving in %{count} separate deliveries.
62
+ dear_customer: Hey %{name},
63
+ instructions: Please review and retain the following information about order %{number} for your records.
64
+ subject: Order Confirmation
65
+ thanks: Thank you
66
+ delivery: Delivery
67
+ delivery_numbered: Delivery %{position} of %{count}
68
+ nothing_to_ship: Nothing to ship
69
+ sold_by: Sold by %{sellers}
70
+ store_owner_notification_email:
71
+ heading: New Order Received
72
+ instructions:
73
+ one: You have received a new order.
74
+ other: You have received a new order, split across %{count} seller orders.
75
+ purchase_summary: Order %{number} Summary
76
+ subject: "%{store_name} received a new order"
77
+ order_mailer:
78
+ cancel_email:
79
+ dear_customer: Hey %{name},
80
+ instructions: Your order has been CANCELED. Please retain this cancellation information for your records.
81
+ order_summary_canceled: Order %{number} Summary [CANCELED]
82
+ subject: Cancellation of Order
83
+ thanks: Thank you for
84
+ confirm_email:
85
+ dear_customer: Hey %{name},
86
+ instructions: Please review and retain the following order information for your records.
87
+ order_summary: Order %{number} Summary
88
+ subject: Order Confirmation
89
+ thanks: Thank you
90
+ payment_link_email:
91
+ message: Please click the button below to pay for your order.
92
+ message_copy_link: 'If the button doesn''t work please copy and paste the following link to your browser:'
93
+ pay_for_order: Pay for order
94
+ subject: 'Payment link for order #%{number}'
95
+ po_number: 'PO Number: %{number}'
96
+ store_owner_notification_email:
97
+ heading: New Order Received
98
+ instructions: You have received a new order.
99
+ order_summary: Order %{number} Summary
100
+ subject: "%{store_name} received a new order"
101
+ thanks: Thank you
102
+ store_team: "%{store_name} Team"
103
+ subtotal: 'Subtotal:'
104
+ total: 'Order Total:'
105
+ return_mailer:
106
+ refunded_email:
107
+ dear_customer: Dear %{name},
108
+ instructions: Your return for order %{number} has been refunded.
109
+ refund_summary: Refund Summary
110
+ returned_items: Returned Items
111
+ store_team: "%{store_name} Team"
112
+ subject: Return Refunded
113
+ thanks: Thank you for your business.
114
+ total_refunded: 'Total refunded: %{total}'
115
+ seller_mailer:
116
+ approved_email:
117
+ action: Go to your dashboard
118
+ heading: You're approved
119
+ message: Your application to sell on %{store_name} has been approved. You can now list products and start taking orders.
120
+ subject: You're approved to sell on %{store_name}
121
+ get_in_touch: If you think this is a mistake, reply to this email or contact us at %{store_email}.
122
+ greeting: Hi %{seller_name},
123
+ rejected_email:
124
+ heading: About your application
125
+ message: Your application to sell on %{store_name} has not been accepted.
126
+ subject: Your application to sell on %{store_name}
127
+ suspended_email:
128
+ heading: Your account has been suspended
129
+ message: Selling on %{store_name} has been paused for your account. Your products and order history are unaffected.
130
+ subject: Your %{store_name} account has been suspended
131
+ shipment_mailer:
132
+ shipped_email:
133
+ dear_customer: Dear %{name},
134
+ instructions: Your order %{number} has been shipped
135
+ shipment_summary: Shipment Summary for order
136
+ shipping_method: 'Shipping method: %{shipping_method}'
137
+ store_team: "%{store_name} Team"
138
+ subject: Shipment Notification
139
+ thanks: Thank you for your business.
140
+ track_information: 'Tracking Information: %{tracking}'
141
+ track_link: 'Tracking Link: %{url}'
@@ -21,6 +21,7 @@ module Spree
21
21
  config.after_initialize do
22
22
  Spree.subscribers.concat [
23
23
  Spree::OrderEmailSubscriber,
24
+ Spree::OrderGroupEmailSubscriber,
24
25
  Spree::FulfillmentEmailSubscriber,
25
26
  Spree::ReturnEmailSubscriber,
26
27
  Spree::NewsletterSubscriberEmailSubscriber,
@@ -0,0 +1,30 @@
1
+ require 'spree/core/previews/preview_data'
2
+
3
+ # Preview the purchase confirmation for a split checkout at
4
+ # /rails/mailers/spree/order_group
5
+ class Spree::OrderGroupPreview < ActionMailer::Preview
6
+ include Spree::PreviewData::LocaleParam
7
+
8
+ def confirm_email
9
+ Spree::OrderGroupMailer.confirm_email(order_group)
10
+ end
11
+
12
+ def store_owner_notification_email
13
+ Spree::OrderGroupMailer.store_owner_notification_email(order_group)
14
+ end
15
+
16
+ private
17
+
18
+ # The most recent split checkout. Nothing to preview until a store has one —
19
+ # a group only exists where a basket spanned several sellers.
20
+ #
21
+ # The locale the preview toolbar asks for is applied to the children in
22
+ # memory (never saved), because a group reads its locale from them.
23
+ def order_group
24
+ group = Spree::OrderGroup.last
25
+ return group if group.nil? || locale.blank?
26
+
27
+ group.orders.load.each { |order| order.locale = locale }
28
+ group
29
+ end
30
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_emails
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.beta2
4
+ version: 6.0.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Schofield
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2026-09-17 00:00:00.000000000 Z
13
+ date: 2026-09-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: spree
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 6.0.0.beta2
21
+ version: 6.0.0.beta3
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - '='
27
27
  - !ruby/object:Gem::Version
28
- version: 6.0.0.beta2
28
+ version: 6.0.0.beta3
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: email_spec
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -59,6 +59,7 @@ files:
59
59
  - app/mailers/spree/digital_asset_mailer.rb
60
60
  - app/mailers/spree/fulfillment_mailer.rb
61
61
  - app/mailers/spree/newsletter_mailer.rb
62
+ - app/mailers/spree/order_group_mailer.rb
62
63
  - app/mailers/spree/order_mailer.rb
63
64
  - app/mailers/spree/return_mailer.rb
64
65
  - app/mailers/spree/seller_mailer.rb
@@ -70,6 +71,7 @@ files:
70
71
  - app/subscribers/spree/fulfillment_email_subscriber.rb
71
72
  - app/subscribers/spree/newsletter_subscriber_email_subscriber.rb
72
73
  - app/subscribers/spree/order_email_subscriber.rb
74
+ - app/subscribers/spree/order_group_email_subscriber.rb
73
75
  - app/subscribers/spree/return_email_subscriber.rb
74
76
  - app/subscribers/spree/seller_email_subscriber.rb
75
77
  - app/views/spree/company_mailer/invitation_email.html.erb
@@ -84,6 +86,10 @@ files:
84
86
  - app/views/spree/fulfillment_mailer/fulfilled_email.text.erb
85
87
  - app/views/spree/newsletter_mailer/email_confirmation.html.erb
86
88
  - app/views/spree/newsletter_mailer/email_confirmation.text.erb
89
+ - app/views/spree/order_group_mailer/confirm_email.html.erb
90
+ - app/views/spree/order_group_mailer/confirm_email.text.erb
91
+ - app/views/spree/order_group_mailer/store_owner_notification_email.html.erb
92
+ - app/views/spree/order_group_mailer/store_owner_notification_email.text.erb
87
93
  - app/views/spree/order_mailer/cancel_email.html.erb
88
94
  - app/views/spree/order_mailer/cancel_email.text.erb
89
95
  - app/views/spree/order_mailer/confirm_email.html.erb
@@ -99,21 +105,28 @@ files:
99
105
  - app/views/spree/seller_mailer/rejected_email.text.erb
100
106
  - app/views/spree/seller_mailer/suspended_email.html.erb
101
107
  - app/views/spree/seller_mailer/suspended_email.text.erb
108
+ - app/views/spree/shared/_fulfillment_group_section.html.erb
109
+ - app/views/spree/shared/_fulfillment_group_section.text.erb
102
110
  - app/views/spree/shared/_item_thumbnail_link.html.erb
103
111
  - app/views/spree/shared/_order_summary_section.html.erb
104
112
  - app/views/spree/shared/_po_number.text.erb
113
+ - app/views/spree/shared/_purchase_totals.html.erb
114
+ - app/views/spree/shared/_purchase_totals.text.erb
105
115
  - app/views/spree/shared/_purchased_items_table.html.erb
106
116
  - app/views/spree/shared/_purchased_items_table.text.erb
107
117
  - app/views/spree/shared/purchased_items_table/_line_item.html.erb
108
118
  - app/views/spree/shared/purchased_items_table/_subtotal.html.erb
109
119
  - app/views/spree/shared/purchased_items_table/_summary_row.html.erb
110
120
  - app/views/spree/shared/purchased_items_table/_total.html.erb
121
+ - config/i18n-tasks.yml
122
+ - config/locales/en.yml
111
123
  - lib/generators/spree/emails/install/install_generator.rb
112
124
  - lib/spree/emails.rb
113
125
  - lib/spree/emails/engine.rb
114
126
  - lib/spree/emails/previews/customer_preview.rb
115
127
  - lib/spree/emails/previews/fulfillment_preview.rb
116
128
  - lib/spree/emails/previews/newsletter_preview.rb
129
+ - lib/spree/emails/previews/order_group_preview.rb
117
130
  - lib/spree/emails/previews/order_preview.rb
118
131
  - lib/spree/emails/previews/return_preview.rb
119
132
  - lib/spree_emails.rb
@@ -122,9 +135,9 @@ licenses:
122
135
  - BSD-3-Clause
123
136
  metadata:
124
137
  bug_tracker_uri: https://github.com/spree/spree/issues
125
- changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.0.beta2
138
+ changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.0.beta3
126
139
  documentation_uri: https://docs.spreecommerce.org/
127
- source_code_uri: https://github.com/spree/spree/tree/v6.0.0.beta2
140
+ source_code_uri: https://github.com/spree/spree/tree/v6.0.0.beta3
128
141
  post_install_message:
129
142
  rdoc_options: []
130
143
  require_paths: