spree_emails 6.0.0.beta4 → 6.0.0.rc1
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 +4 -4
- data/README.md +30 -74
- data/Rakefile +23 -0
- data/app/mailers/spree/company_mailer.rb +4 -7
- data/app/mailers/spree/customer_mailer.rb +6 -8
- data/app/mailers/spree/digital_asset_mailer.rb +18 -11
- data/app/mailers/spree/fulfillment_mailer.rb +11 -7
- data/app/mailers/spree/newsletter_mailer.rb +1 -2
- data/app/mailers/spree/order_group_mailer.rb +16 -20
- data/app/mailers/spree/order_mailer.rb +15 -20
- data/app/mailers/spree/return_mailer.rb +10 -5
- data/app/mailers/spree/seller_mailer.rb +8 -13
- data/app/models/spree/emails/amount_line.rb +32 -0
- data/app/serializers/spree/emails/address_serializer.rb +6 -0
- data/app/serializers/spree/emails/amount_line_serializer.rb +17 -0
- data/app/serializers/spree/emails/applied_promotion_serializer.rb +6 -0
- data/app/serializers/spree/emails/delivery_method_serializer.rb +6 -0
- data/app/serializers/spree/emails/delivery_rate_serializer.rb +10 -0
- data/app/serializers/spree/emails/delivery_serializer.rb +6 -0
- data/app/serializers/spree/emails/fee_serializer.rb +6 -0
- data/app/serializers/spree/emails/freight_summary_serializer.rb +6 -0
- data/app/serializers/spree/emails/fulfillment_group_serializer.rb +22 -0
- data/app/serializers/spree/emails/fulfillment_serializer.rb +19 -0
- data/app/serializers/spree/emails/gift_card_serializer.rb +6 -0
- data/app/serializers/spree/emails/line_item_serializer.rb +22 -0
- data/app/serializers/spree/emails/market_serializer.rb +6 -0
- data/app/serializers/spree/emails/option_value_serializer.rb +6 -0
- data/app/serializers/spree/emails/order_group_serializer.rb +60 -0
- data/app/serializers/spree/emails/order_serializer.rb +25 -0
- data/app/serializers/spree/emails/parcel_item_serializer.rb +36 -0
- data/app/serializers/spree/emails/payment_method_serializer.rb +6 -0
- data/app/serializers/spree/emails/payment_serializer.rb +9 -0
- data/app/serializers/spree/emails/purchase_summary_attributes.rb +41 -0
- data/app/serializers/spree/emails/purchased_item_attributes.rb +28 -0
- data/app/serializers/spree/emails/return_serializer.rb +17 -0
- data/app/serializers/spree/emails/stock_location_serializer.rb +6 -0
- data/app/services/spree/emails/samples/base.rb +79 -0
- data/app/services/spree/emails/samples/company_invitation.rb +19 -0
- data/app/services/spree/emails/samples/data_export.rb +11 -0
- data/app/services/spree/emails/samples/downloads.rb +28 -0
- data/app/services/spree/emails/samples/fulfillment.rb +33 -0
- data/app/services/spree/emails/samples/newsletter_confirmation.rb +11 -0
- data/app/services/spree/emails/samples/order.rb +22 -0
- data/app/services/spree/emails/samples/order_group.rb +22 -0
- data/app/services/spree/emails/samples/password_reset.rb +15 -0
- data/app/services/spree/emails/samples/payment_link.rb +17 -0
- data/app/services/spree/emails/samples/return.rb +29 -0
- data/app/subscribers/spree/order_email_subscriber.rb +2 -2
- data/app/subscribers/spree/order_group_email_subscriber.rb +1 -1
- data/app/subscribers/spree/return_email_subscriber.rb +2 -0
- data/app/views/spree/company_mailer/invitation_email.liquid +13 -0
- data/app/views/spree/customer_mailer/data_export_email.liquid +18 -0
- data/app/views/spree/customer_mailer/password_reset_email.liquid +14 -0
- data/app/views/spree/digital_asset_mailer/files_ready_email.liquid +23 -0
- data/app/views/spree/fulfillment_mailer/fulfilled_email.liquid +21 -0
- data/app/views/spree/newsletter_mailer/email_confirmation.liquid +13 -0
- data/app/views/spree/order_group_mailer/confirm_email.liquid +35 -0
- data/app/views/spree/order_group_mailer/store_owner_notification_email.liquid +11 -0
- data/app/views/spree/order_mailer/cancel_email.liquid +12 -0
- data/app/views/spree/order_mailer/confirm_email.liquid +12 -0
- data/app/views/spree/order_mailer/payment_link_email.liquid +12 -0
- data/app/views/spree/order_mailer/store_owner_notification_email.liquid +11 -0
- data/app/views/spree/return_mailer/refunded_email.liquid +18 -0
- data/app/views/spree/seller_mailer/approved_email.liquid +13 -0
- data/app/views/spree/seller_mailer/rejected_email.liquid +11 -0
- data/app/views/spree/seller_mailer/suspended_email.liquid +11 -0
- data/app/views/spree/shared/_fulfillment_group.liquid +20 -0
- data/app/views/spree/shared/_line_item.liquid +29 -0
- data/app/views/spree/shared/_order_summary.liquid +17 -0
- data/app/views/spree/shared/_purchase_totals.liquid +28 -0
- data/config/initializers/typelizer.rb +60 -0
- data/config/locales/ar.yml +40 -0
- data/config/locales/be.yml +37 -0
- data/config/locales/bg.yml +31 -0
- data/config/locales/ca.yml +35 -0
- data/config/locales/cs.yml +38 -0
- data/config/locales/da.yml +37 -0
- data/config/locales/de-CH.yml +11 -0
- data/config/locales/de.yml +38 -0
- data/config/locales/el.yml +37 -0
- data/config/locales/en.yml +0 -25
- data/config/locales/es-CL.yml +21 -0
- data/config/locales/es-EC.yml +22 -0
- data/config/locales/es-MX.yml +26 -0
- data/config/locales/es.yml +40 -0
- data/config/locales/et.yml +31 -0
- data/config/locales/fa.yml +37 -0
- data/config/locales/fi.yml +37 -0
- data/config/locales/fr.yml +38 -0
- data/config/locales/hu.yml +37 -0
- data/config/locales/id.yml +37 -0
- data/config/locales/it.yml +38 -0
- data/config/locales/ja.yml +36 -0
- data/config/locales/km.yml +37 -0
- data/config/locales/ko.yml +36 -0
- data/config/locales/ku.yml +37 -0
- data/config/locales/lt.yml +37 -0
- data/config/locales/lv.yml +39 -0
- data/config/locales/nb.yml +37 -0
- data/config/locales/ne.yml +37 -0
- data/config/locales/nl.yml +38 -0
- data/config/locales/pl.yml +39 -0
- data/config/locales/pt-BR.yml +34 -0
- data/config/locales/pt.yml +34 -0
- data/config/locales/ro.yml +37 -0
- data/config/locales/ru.yml +38 -0
- data/config/locales/sk.yml +31 -0
- data/config/locales/sl-SI.yml +31 -0
- data/config/locales/sv.yml +37 -0
- data/config/locales/th.yml +37 -0
- data/config/locales/tr.yml +38 -0
- data/config/locales/uk.yml +42 -0
- data/config/locales/vi.yml +35 -0
- data/config/locales/zh-CN.yml +38 -0
- data/config/locales/zh-TW.yml +40 -0
- data/lib/spree/emails/engine.rb +27 -3
- data/lib/spree/emails/previews/company_preview.rb +10 -0
- data/lib/spree/emails/previews/customer_preview.rb +4 -0
- data/lib/spree/emails/previews/digital_asset_preview.rb +20 -0
- metadata +107 -55
- data/app/helpers/spree/base_helper.rb +0 -45
- data/app/helpers/spree/digital_asset_helper.rb +0 -16
- data/app/helpers/spree/fulfillment_helper.rb +0 -12
- data/app/helpers/spree/mail_helper.rb +0 -10
- data/app/views/spree/company_mailer/invitation_email.html.erb +0 -8
- data/app/views/spree/company_mailer/invitation_email.text.erb +0 -11
- data/app/views/spree/customer_mailer/data_export_email.html.erb +0 -12
- data/app/views/spree/customer_mailer/data_export_email.text.erb +0 -9
- data/app/views/spree/customer_mailer/password_reset_email.html.erb +0 -10
- data/app/views/spree/customer_mailer/password_reset_email.text.erb +0 -13
- data/app/views/spree/digital_asset_mailer/files_ready_email.html.erb +0 -20
- data/app/views/spree/digital_asset_mailer/files_ready_email.text.erb +0 -10
- data/app/views/spree/fulfillment_mailer/fulfilled_email.html.erb +0 -22
- data/app/views/spree/fulfillment_mailer/fulfilled_email.text.erb +0 -18
- data/app/views/spree/newsletter_mailer/email_confirmation.html.erb +0 -12
- data/app/views/spree/newsletter_mailer/email_confirmation.text.erb +0 -9
- data/app/views/spree/order_group_mailer/confirm_email.html.erb +0 -38
- data/app/views/spree/order_group_mailer/confirm_email.text.erb +0 -26
- data/app/views/spree/order_group_mailer/store_owner_notification_email.html.erb +0 -14
- data/app/views/spree/order_group_mailer/store_owner_notification_email.text.erb +0 -11
- data/app/views/spree/order_mailer/cancel_email.html.erb +0 -12
- data/app/views/spree/order_mailer/cancel_email.text.erb +0 -13
- data/app/views/spree/order_mailer/confirm_email.html.erb +0 -12
- data/app/views/spree/order_mailer/confirm_email.text.erb +0 -13
- data/app/views/spree/order_mailer/payment_link_email.html.erb +0 -11
- data/app/views/spree/order_mailer/store_owner_notification_email.html.erb +0 -11
- data/app/views/spree/order_mailer/store_owner_notification_email.text.erb +0 -13
- data/app/views/spree/return_mailer/refunded_email.html.erb +0 -22
- data/app/views/spree/return_mailer/refunded_email.text.erb +0 -20
- data/app/views/spree/seller_mailer/approved_email.html.erb +0 -8
- data/app/views/spree/seller_mailer/approved_email.text.erb +0 -8
- data/app/views/spree/seller_mailer/rejected_email.html.erb +0 -6
- data/app/views/spree/seller_mailer/rejected_email.text.erb +0 -7
- data/app/views/spree/seller_mailer/suspended_email.html.erb +0 -6
- data/app/views/spree/seller_mailer/suspended_email.text.erb +0 -7
- data/app/views/spree/shared/_fulfillment_group_section.html.erb +0 -37
- data/app/views/spree/shared/_fulfillment_group_section.text.erb +0 -12
- data/app/views/spree/shared/_item_thumbnail_link.html.erb +0 -18
- data/app/views/spree/shared/_order_summary_section.html.erb +0 -20
- data/app/views/spree/shared/_po_number.text.erb +0 -6
- data/app/views/spree/shared/_purchase_totals.html.erb +0 -62
- data/app/views/spree/shared/_purchase_totals.text.erb +0 -24
- data/app/views/spree/shared/_purchased_items_table.html.erb +0 -41
- data/app/views/spree/shared/_purchased_items_table.text.erb +0 -28
- data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +0 -24
- data/app/views/spree/shared/purchased_items_table/_subtotal.html.erb +0 -3
- data/app/views/spree/shared/purchased_items_table/_summary_row.html.erb +0 -14
- data/app/views/spree/shared/purchased_items_table/_total.html.erb +0 -4
- data/config/i18n-tasks.yml +0 -22
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
# One real parcel of a purchase: what it carries, who sold it and what it
|
|
4
|
+
# cost to deliver.
|
|
5
|
+
class FulfillmentGroupSerializer
|
|
6
|
+
include Alba::Resource
|
|
7
|
+
|
|
8
|
+
attributes :name
|
|
9
|
+
|
|
10
|
+
attribute :display_cost do |group|
|
|
11
|
+
group.display_cost.to_s
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
attribute :seller_names do |group|
|
|
15
|
+
group.sellers.map(&:name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
many :manifest, key: :items, source: proc { manifest.select(&:line_item) },
|
|
19
|
+
resource: Spree::Emails::ParcelItemSerializer
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
class FulfillmentSerializer < Spree::Api::V3::FulfillmentSerializer
|
|
4
|
+
typelize delivery_method_name: [:string, nullable: true]
|
|
5
|
+
|
|
6
|
+
attribute :delivery_method_name do |fulfillment|
|
|
7
|
+
fulfillment.delivery_method&.name
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
many :deliveries, resource: Spree::Emails::DeliverySerializer
|
|
11
|
+
one :delivery_method, resource: Spree::Emails::DeliveryMethodSerializer
|
|
12
|
+
one :stock_location, resource: Spree::Emails::StockLocationSerializer
|
|
13
|
+
many :delivery_rates, resource: Spree::Emails::DeliveryRateSerializer
|
|
14
|
+
|
|
15
|
+
many :manifest, key: :manifest_items, source: proc { manifest.select(&:line_item) },
|
|
16
|
+
resource: Spree::Emails::ParcelItemSerializer
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
class LineItemSerializer < Spree::Api::V3::LineItemSerializer
|
|
4
|
+
include Spree::Emails::PurchasedItemAttributes
|
|
5
|
+
|
|
6
|
+
many :option_values, resource: Spree::Emails::OptionValueSerializer
|
|
7
|
+
|
|
8
|
+
typelize sku: [:string, nullable: true], display_amount: :string,
|
|
9
|
+
url: [:string, nullable: true], image_url: [:string, nullable: true]
|
|
10
|
+
|
|
11
|
+
attributes :sku
|
|
12
|
+
|
|
13
|
+
# Price times quantity, before discounts — what the line cost.
|
|
14
|
+
attribute :display_amount do |line_item|
|
|
15
|
+
line_item.display_amount.to_s
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The full-size image; emails show the thumbnail in `image_url`.
|
|
19
|
+
attributes :thumbnail_url, if: proc { false }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
# A purchase that divided into several orders, as its confirmation reads
|
|
4
|
+
# it: every item, the parcels it ships in, and one set of totals.
|
|
5
|
+
class OrderGroupSerializer < Spree::Api::V3::OrderGroupSerializer
|
|
6
|
+
include Spree::Emails::PurchaseSummaryAttributes
|
|
7
|
+
|
|
8
|
+
typelize po_number: [:string, nullable: true], order_count: :number,
|
|
9
|
+
delivery_total: :string, display_delivery_total: :string,
|
|
10
|
+
additional_tax_total: :string, display_additional_tax_total: :string,
|
|
11
|
+
gift_card_total: :string, display_gift_card_total: :string
|
|
12
|
+
|
|
13
|
+
attributes :po_number
|
|
14
|
+
|
|
15
|
+
attribute :order_count do |group|
|
|
16
|
+
group.orders.size
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attribute :display_delivery_total do |group|
|
|
20
|
+
group.display_delivery_total.to_s
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attribute :delivery_total do |group|
|
|
24
|
+
group.delivery_total.to_s
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attribute :additional_tax_total do |group|
|
|
28
|
+
group.additional_tax_total.to_s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
attribute :display_additional_tax_total do |group|
|
|
32
|
+
group.display_additional_tax_total.to_s
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
attribute :gift_card_total do |group|
|
|
36
|
+
group.gift_card_total.to_s
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attribute :display_gift_card_total do |group|
|
|
40
|
+
group.display_gift_card_total.to_s
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Every child order in full is what the webhook payload carries; the
|
|
44
|
+
# email reads the purchase-wide fields above instead.
|
|
45
|
+
many :orders, resource: proc { Spree.api.order_serializer }, if: proc { false }
|
|
46
|
+
|
|
47
|
+
many :fulfillment_groups, resource: Spree::Emails::FulfillmentGroupSerializer
|
|
48
|
+
|
|
49
|
+
# What no parcel carries — a download, an emailed gift card.
|
|
50
|
+
many :unfulfilled_items,
|
|
51
|
+
source: proc { unfulfilled_line_items },
|
|
52
|
+
resource: Spree::Emails::LineItemSerializer
|
|
53
|
+
|
|
54
|
+
# One delivery row for the whole purchase; the parcels break it down.
|
|
55
|
+
many :delivery_lines,
|
|
56
|
+
source: proc { delivery_total.zero? ? [] : [Spree::Emails::AmountLine.new(amount: delivery_total, currency: currency)] },
|
|
57
|
+
resource: Spree::Emails::AmountLineSerializer
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
# An order as its emails read it: the Store API order plus what only an
|
|
4
|
+
# email shows — who to greet, the summary rows and line thumbnails.
|
|
5
|
+
class OrderSerializer < Spree::Api::V3::OrderSerializer
|
|
6
|
+
include Spree::Emails::PurchaseSummaryAttributes
|
|
7
|
+
|
|
8
|
+
many :order_promotions, key: :discounts, resource: Spree::Emails::AppliedPromotionSerializer
|
|
9
|
+
many :fees, resource: Spree::Emails::FeeSerializer
|
|
10
|
+
many :fulfillments, resource: Spree::Emails::FulfillmentSerializer
|
|
11
|
+
many :payments, resource: Spree::Emails::PaymentSerializer
|
|
12
|
+
one :gift_card, resource: Spree::Emails::GiftCardSerializer
|
|
13
|
+
one :market, resource: Spree::Emails::MarketSerializer
|
|
14
|
+
|
|
15
|
+
# One row per delivery rate, at its cost before discounts, so the rows
|
|
16
|
+
# add up to the total once a free-delivery promotion is listed.
|
|
17
|
+
many :delivery_lines,
|
|
18
|
+
source: proc {
|
|
19
|
+
Spree::Emails::AmountLine.group(fulfillments, currency: currency, amount: :cost, keep_zero: true,
|
|
20
|
+
label: ->(fulfillment) { fulfillment.selected_delivery_rate&.name })
|
|
21
|
+
},
|
|
22
|
+
resource: Spree::Emails::AmountLineSerializer
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
# One line as it travels in one parcel. A line packed from two warehouses
|
|
4
|
+
# rides in two parcels, so the quantity and amount are the parcel's share
|
|
5
|
+
# rather than the whole line's.
|
|
6
|
+
class ParcelItemSerializer < Spree::Emails::BaseSerializer
|
|
7
|
+
include Spree::Emails::PurchasedItemAttributes
|
|
8
|
+
|
|
9
|
+
attribute :id do |item|
|
|
10
|
+
item.line_item.prefixed_id
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attribute :name do |item|
|
|
14
|
+
item.line_item.name
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attributes :quantity
|
|
18
|
+
|
|
19
|
+
attribute :sku do |item|
|
|
20
|
+
item.line_item.sku
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attribute :options_text do |item|
|
|
24
|
+
item.line_item.options_text
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attribute :display_price do |item|
|
|
28
|
+
item.line_item.display_price.to_s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
attribute :display_amount do |item|
|
|
32
|
+
Spree::Money.new(item.line_item.price * item.quantity, currency: item.line_item.currency).to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
# What an email shows for a whole purchase — who to greet, the items and
|
|
4
|
+
# the summary rows — for both an order and a multi-seller purchase. The
|
|
5
|
+
# `spree/shared/purchase_totals` partial reads these names from either.
|
|
6
|
+
module PurchaseSummaryAttributes
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
typelize customer_name: :string, display_total_minus_store_credits: :string
|
|
11
|
+
|
|
12
|
+
attribute :customer_name do |purchase|
|
|
13
|
+
purchase.name.presence || I18n.t('spree.customer')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attribute :display_total_minus_store_credits do |purchase|
|
|
17
|
+
purchase.display_total_minus_store_credits.to_s
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
many :line_items, key: :items, resource: Spree::Emails::LineItemSerializer
|
|
21
|
+
one :billing_address, resource: Spree::Emails::AddressSerializer
|
|
22
|
+
one :shipping_address, resource: Spree::Emails::AddressSerializer
|
|
23
|
+
|
|
24
|
+
many :promotion_discounts,
|
|
25
|
+
source: proc { Spree::Emails::AmountLine.group(discounts.promotion, currency: currency) },
|
|
26
|
+
resource: Spree::Emails::AmountLineSerializer
|
|
27
|
+
|
|
28
|
+
many :manual_discounts,
|
|
29
|
+
source: proc { Spree::Emails::AmountLine.group(discounts.manual, currency: currency) },
|
|
30
|
+
resource: Spree::Emails::AmountLineSerializer
|
|
31
|
+
|
|
32
|
+
# A multi-seller checkout apportions an order-level fee into one row
|
|
33
|
+
# per child, all under one label; summed back, it is the one charge the
|
|
34
|
+
# customer saw.
|
|
35
|
+
many :fee_lines,
|
|
36
|
+
source: proc { Spree::Emails::AmountLine.group(fees, currency: currency) },
|
|
37
|
+
resource: Spree::Emails::AmountLineSerializer
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
# What an email shows for a purchased line besides its Store API fields: a
|
|
4
|
+
# link to the product on the storefront and a thumbnail. Shared by the line
|
|
5
|
+
# item and parcel item serializers.
|
|
6
|
+
module PurchasedItemAttributes
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
include Spree::ImagesHelper
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
attribute :url do |item|
|
|
12
|
+
product = purchased_line_item(item).product
|
|
13
|
+
"#{params[:storefront_url]}/products/#{product.slug}" if product
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attribute :image_url do |item|
|
|
17
|
+
spree_image_url(purchased_line_item(item).thumbnail, variant: :small)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def purchased_line_item(item)
|
|
24
|
+
item.is_a?(Spree::LineItem) ? item : item.line_item
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
class ReturnSerializer < Spree::Api::V3::ReturnSerializer
|
|
4
|
+
typelize display_refunded_total: :string
|
|
5
|
+
|
|
6
|
+
# What was actually paid back — not the Store API's refund_total, which
|
|
7
|
+
# is the figure the return was expected to refund.
|
|
8
|
+
attribute :display_refunded_total do |return_record|
|
|
9
|
+
return_record.display_refunded_total.to_s
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
many :returned_items,
|
|
13
|
+
source: proc { return_line_items.filter_map(&:line_item).uniq },
|
|
14
|
+
resource: Spree::Emails::LineItemSerializer
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
# Builds what an email's template receives, for previewing a template
|
|
5
|
+
# and checking it before it is published: from the store's most recent
|
|
6
|
+
# matching record, or one the merchant picks. Values that would carry a
|
|
7
|
+
# token (reset, invitation, download links) are always placeholders.
|
|
8
|
+
class Base
|
|
9
|
+
# @return [String, nil] the kind of record the merchant can pick
|
|
10
|
+
# ("order", "order_group", "fulfillment", "return"), or nil when the
|
|
11
|
+
# email needs none
|
|
12
|
+
def self.record_type
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [Array<String>] the permission keys a caller needs to see this
|
|
17
|
+
# sample, since it shows a real record's data
|
|
18
|
+
def self.required_permissions
|
|
19
|
+
record_type ? %w[read_orders] : []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
attr_reader :store, :record_id
|
|
23
|
+
|
|
24
|
+
# @param store [Spree::Store]
|
|
25
|
+
# @param record_id [String, nil] a prefixed id of the record to preview with
|
|
26
|
+
def initialize(store:, record_id: nil)
|
|
27
|
+
@store = store
|
|
28
|
+
@record_id = record_id.presence
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Hash] the template's variables, before `store` and `locale` are added
|
|
32
|
+
def variables
|
|
33
|
+
raise NotImplementedError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @param limit [Integer]
|
|
37
|
+
# @return [Array<Spree::EmailTemplates::SampleRecord>] the store's latest
|
|
38
|
+
# records the email can be previewed with; empty when it needs none
|
|
39
|
+
def recent_records(limit: 5)
|
|
40
|
+
return [] unless self.class.record_type
|
|
41
|
+
|
|
42
|
+
records.limit(limit).map do |record|
|
|
43
|
+
Spree::EmailTemplates::SampleRecord.new(
|
|
44
|
+
id: record.prefixed_id, label: record.try(:number).presence || record.prefixed_id, created_at: record.created_at
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [String] the currency the email's amounts are in
|
|
50
|
+
def currency
|
|
51
|
+
(self.class.record_type && record.try(:currency)).presence || store.default_currency
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
protected
|
|
55
|
+
|
|
56
|
+
def record
|
|
57
|
+
@record ||= if record_id
|
|
58
|
+
records.find_by_prefix_id!(record_id)
|
|
59
|
+
else
|
|
60
|
+
records.first || raise(Spree::EmailTemplates::NoSampleRecord, I18n.t('spree.email_templates.no_sample_record', record: self.class.record_type.to_s.humanize.downcase))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Every lookup goes through the store, so another store's record never answers.
|
|
65
|
+
def records
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def data(object, serializer)
|
|
70
|
+
Spree::Emails::TemplateData.call(object, serializer, store: store, currency: currency)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def placeholder_url(path)
|
|
74
|
+
"#{store.storefront_url.to_s.chomp('/')}/#{path}?token=preview"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
class CompanyInvitation < Base
|
|
5
|
+
def self.required_permissions
|
|
6
|
+
%w[read_customers]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def variables
|
|
10
|
+
{
|
|
11
|
+
company: data(store.companies.order(created_at: :desc).first || Spree::Company.new(name: 'Acme Corporation', store: store),
|
|
12
|
+
Spree.api.company_serializer),
|
|
13
|
+
accept_url: placeholder_url('account/company-invitation')
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
# The files-ready email. Lists the order's own downloads when it has any,
|
|
5
|
+
# always with placeholder links.
|
|
6
|
+
class Downloads < Order
|
|
7
|
+
def variables
|
|
8
|
+
{
|
|
9
|
+
order: data(record, Spree::Emails::OrderSerializer),
|
|
10
|
+
downloads: downloads,
|
|
11
|
+
resend: false
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def downloads
|
|
18
|
+
links = record.digital_links.includes(digital_asset: { attachment_attachment: :blob }).to_a
|
|
19
|
+
return [{ filename: 'guide.pdf', url: placeholder_url('downloads'), expires_at: nil }] if links.empty?
|
|
20
|
+
|
|
21
|
+
links.map do |link|
|
|
22
|
+
{ filename: link.filename.to_s, url: placeholder_url('downloads'), expires_at: link.expires_at&.iso8601 }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
class Fulfillment < Base
|
|
5
|
+
def self.required_permissions
|
|
6
|
+
%w[read_orders read_fulfillments]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.record_type
|
|
10
|
+
'fulfillment'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def variables
|
|
14
|
+
{
|
|
15
|
+
fulfillment: data(record, Spree::Emails::FulfillmentSerializer),
|
|
16
|
+
order: data(record.order, Spree::Emails::OrderSerializer),
|
|
17
|
+
resend: false
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def currency
|
|
22
|
+
record.order.currency
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
def records
|
|
28
|
+
store.fulfillments.order(created_at: :desc)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
# Order confirmation and cancellation.
|
|
5
|
+
class Order < Base
|
|
6
|
+
def self.record_type
|
|
7
|
+
'order'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def variables
|
|
11
|
+
{ order: data(record, Spree::Emails::OrderSerializer), resend: false }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def records
|
|
17
|
+
store.orders.complete.order(completed_at: :desc)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
# The confirmation of a purchase that divided into several orders.
|
|
5
|
+
class OrderGroup < Base
|
|
6
|
+
def self.record_type
|
|
7
|
+
'order_group'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def variables
|
|
11
|
+
{ order_group: data(record, Spree::Emails::OrderGroupSerializer), resend: false }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def records
|
|
17
|
+
store.order_groups.order(created_at: :desc)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
class PasswordReset < Base
|
|
5
|
+
def variables
|
|
6
|
+
{
|
|
7
|
+
customer: data(Spree.customer_class.new(first_name: 'Jane', last_name: 'Doe', email: 'jane@example.com'),
|
|
8
|
+
Spree.api.customer_serializer),
|
|
9
|
+
reset_url: placeholder_url('account/reset-password')
|
|
10
|
+
}
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
class PaymentLink < Order
|
|
5
|
+
def variables
|
|
6
|
+
{ order: data(record, Spree::Emails::OrderSerializer), payment_url: placeholder_url('checkout/payment') }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
protected
|
|
10
|
+
|
|
11
|
+
def records
|
|
12
|
+
store.orders.order(created_at: :desc)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Emails
|
|
3
|
+
module Samples
|
|
4
|
+
class Return < Base
|
|
5
|
+
def self.record_type
|
|
6
|
+
'return'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def variables
|
|
10
|
+
{
|
|
11
|
+
return: data(record, Spree::Emails::ReturnSerializer),
|
|
12
|
+
order: data(record.order, Spree::Emails::OrderSerializer),
|
|
13
|
+
resend: false
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def currency
|
|
18
|
+
record.order.currency
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
def records
|
|
24
|
+
store.returns.order(created_at: :desc)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -20,7 +20,7 @@ module Spree
|
|
|
20
20
|
|
|
21
21
|
def send_customer_confirmation(order, event)
|
|
22
22
|
return if order.confirmation_delivered?
|
|
23
|
-
return if event.
|
|
23
|
+
return if event.metadata['notify_customer'] == false
|
|
24
24
|
return unless order.store.prefers_send_consumer_transactional_emails?
|
|
25
25
|
|
|
26
26
|
OrderMailer.confirm_email(order.id).deliver_later
|
|
@@ -46,7 +46,7 @@ module Spree
|
|
|
46
46
|
def send_cancel_email(event)
|
|
47
47
|
order = find_order(event)
|
|
48
48
|
return unless order
|
|
49
|
-
return if event.
|
|
49
|
+
return if event.metadata['notify_customer'] == false
|
|
50
50
|
|
|
51
51
|
store = order.store
|
|
52
52
|
return unless store.prefers_send_consumer_transactional_emails?
|
|
@@ -27,7 +27,7 @@ module Spree
|
|
|
27
27
|
# about the sale.
|
|
28
28
|
def send_customer_confirmation(order_group, event)
|
|
29
29
|
return if order_group.confirmation_delivered?
|
|
30
|
-
return if event.
|
|
30
|
+
return if event.metadata['notify_customer'] == false
|
|
31
31
|
return unless order_group.store.prefers_send_consumer_transactional_emails?
|
|
32
32
|
|
|
33
33
|
OrderGroupMailer.confirm_email(order_group.id).deliver_later
|
|
@@ -10,6 +10,8 @@ module Spree
|
|
|
10
10
|
|
|
11
11
|
store = return_record.store
|
|
12
12
|
return unless store.prefers_send_consumer_transactional_emails?
|
|
13
|
+
# A return owed nothing closes without a refund, so there is none to announce.
|
|
14
|
+
return if return_record.refunded_total.zero?
|
|
13
15
|
|
|
14
16
|
ReturnMailer.refunded_email(return_record.id).deliver_later
|
|
15
17
|
end
|