CoolCMS API

OrderEmailGenerator
in package

FinalYes

Renders the transactional order e-mails and hands them to the e-mail queue owner.

E-mails are never sent directly. Each prepare*() method renders one and returns a PreparedOrderEmail; the caller (OrderTransitionManager) enqueues it through EmailQueueManager::enqueue() on its own DBAL connection, so the insert joins the caller's transaction. This class only renders. Rendering (Latte and I/O) runs before the final transaction on purpose: inside it, it would needlessly widen the lock window on orders.

The render is a local minimal copy of SendEmailTrait::setTemplate() (e-mail template path, email.latte, {#BODY#}, Latte string loader, DateHelper, PriceLatteExtension). The trait is not used directly because this service is not a Manager and has no settingContext/findBy().

Template sources:

  • prepareStatusEmail(): OrderStatusText.emailSubject/emailBody for the order language;
  • prepareDefaultEmail(): system template ES_ORDER_CHANGED through EmailManager;
  • prepareExpeditionEmail(): ShipperText.emailSubject/emailBody of order.expeditionShipper, guarded by Shipper::getSendEmail();
  • prepareNewOrderAdminEmail(): system template ES_NEW_ORDER to the shop administrator (not the customer), queued by OrderAdminNoticeManager.

Every prepare*() returns null on an empty template or a failed guard (including a system template or its language turned off in the admin), and also when the render fails (see renderTemplate(); the error is logged to the eshop.general channel). Nothing is queued then, instead of the customer receiving an empty e-mail with no trace.

The language is order.language, falling back to LanguageManager::getDefaultLanguageId(). A missing or empty template is not looked up in another language: it yields null.

IMPORTANT: amounts and dates are formatted by the localization and language of the order, not of the request. A transition is triggered by the admin (Czech localization) or by cron (none), so without the override an English customer would get Czech price and date formats. The render runs inside PriceFormatContext::runWith() and dates go through DocumentLocale.

Tags
phpstan-import-type

TOrderGraph from OrderCalculator

Table of Contents

Constants

DEFAULT_EMAIL_KEY  : string = 'ES_ORDER_CHANGED'
NEW_ORDER_EMAIL_KEY  : string = 'ES_NEW_ORDER'
SETTING_MODULE_CORE  : int = 0
SETTING_MODULE_SYSTEM  : int = 1
VOUCHER_EMAIL_KEY  : string = 'ES_NEW_VOUCHER'

Properties

$calculator  : OrderCalculator
$emailManager  : EmailManager
$languageManager  : LanguageManager
$priceFormatContext  : PriceFormatContext
$priceLatteExtension  : PriceLatteExtension
$settingContext  : SettingContext
$translator  : Translator

Methods

__construct()  : mixed
prepareDefaultEmail()  : PreparedOrderEmail|null
Renders the system template `ES_ORDER_CHANGED` (value `status` = status name).
prepareExpeditionEmail()  : PreparedOrderEmail|null
Renders the dispatch notice from `ShipperText` of `order.expeditionShipper` and the order expedition columns.
prepareNewOrderAdminEmail()  : PreparedOrderEmail|null
Renders the system template `ES_NEW_ORDER`: the notice to the shop administrator about a new order from the checkout (the customer gets the status e-mail, not this one).
prepareStatusEmail()  : PreparedOrderEmail|null
Renders the e-mail from the status template in the order language.
prepareVoucherEmail()  : PreparedOrderEmail|null
Renders the system template `ES_NEW_VOUCHER` (compensation voucher from {@see VoucherGenerator}).
recapValues()  : array<string, mixed>
Builds the variables of the order e-mail templates.
adminEmail()  : string|null
Seller e-mail of the order, falling back to the site mailbox `1/email.address`; `null` when neither is valid.
customerEmail()  : string|null
formatMoney()  : string
inOrderFormat()  : PreparedOrderEmail|null
Runs the render in the localization and language of the order. An order without localization (historical) falls back to the request localization.
isTransferPayment()  : bool
Tells whether the payment is a bank transfer: the method sends a proforma invoice and has no payment gateway (same rule as `OrderCheckoutManager::targetStatusKey()`).
orderLocalization()  : object|null
Returns the order localization (snapshot from checkout/admin).
render()  : PreparedOrderEmail|null
Renders subject and body; a failed render (see {@see renderTemplate()}) returns `null`, so no empty e-mail is queued.
renderSubject()  : string
Renders the subject as a Latte string (no wrapper template).
renderTemplate()  : string|null
Renders the e-mail, returning `null` on failure.
resolveLanguageId()  : int
Returns `order.language`, falling back to the site-wide default language.

Constants

Properties

Methods

__construct()

public __construct(SettingContext $settingContext, EmailManager $emailManager, LanguageManager $languageManager, PriceLatteExtension $priceLatteExtension, OrderCalculator $calculator, PriceFormatContext $priceFormatContext, Translator $translator) : mixed
Parameters
$settingContext : SettingContext
$emailManager : EmailManager
$languageManager : LanguageManager
$priceLatteExtension : PriceLatteExtension
$calculator : OrderCalculator
$priceFormatContext : PriceFormatContext
$translator : Translator

prepareDefaultEmail()

Renders the system template `ES_ORDER_CHANGED` (value `status` = status name).

public prepareDefaultEmail(Order $order, OrderStatus $status[, string|null $invoicePdfPath = null ][, string|null $invoiceVariableSymbol = null ]) : PreparedOrderEmail|null

Returns null when the template is missing in the database or empty for the order language. The invoice PDF is attached like in prepareStatusEmail().

IMPORTANT: the created and approved statuses have send_email=0, so this default e-mail is the only one the customer receives. Without the attachment here the order confirmation would never reach the customer by e-mail.

Parameters
$order : Order
$status : OrderStatus
$invoicePdfPath : string|null = null
$invoiceVariableSymbol : string|null = null
Return values
PreparedOrderEmail|null

prepareExpeditionEmail()

Renders the dispatch notice from `ShipperText` of `order.expeditionShipper` and the order expedition columns.

public prepareExpeditionEmail(Order $order) : PreparedOrderEmail|null

Returns null when the shipper is missing, Shipper::getSendEmail() is false, or the template is empty. The status name is read from order.status, which the transition must set to the target status before calling this method (there is no $status parameter).

Parameters
$order : Order
Return values
PreparedOrderEmail|null

prepareNewOrderAdminEmail()

Renders the system template `ES_NEW_ORDER`: the notice to the shop administrator about a new order from the checkout (the customer gets the status e-mail, not this one).

public prepareNewOrderAdminEmail(TOrderGraph $order, string $adminLink) : PreparedOrderEmail|null

Recipient: the seller e-mail of the order (the Invoicer seller of the shop, snapshot on the order), falling back to the site mailbox 1/email.address (the same rule as the reservation notice to a company). The text is in the default site language (the operator), amounts and dates in the order format. The subject is rendered as Latte ({$orderNumber}).

Values (flat, no array access in the template): orderNumber, orderDate, customerName, customerCompany, customerEmail, customerPhone, shippingName, paymentName, totalPrice (payable amount with the currency) and adminLink (absolute link to the order in the administration, '' when no absolute address is known).

Returns null when the template is missing, turned off (the default) or empty in that language, when no recipient address is known, or when the render fails.

Parameters
$order : TOrderGraph
$adminLink : string
Return values
PreparedOrderEmail|null

prepareStatusEmail()

Renders the e-mail from the status template in the order language.

public prepareStatusEmail(Order $order, OrderStatus $status, string|null $invoicePdfPath[, string|null $invoiceVariableSymbol = null ]) : PreparedOrderEmail|null

Returns null for an empty template (missing text, or empty subject or body; a status without e-mail, e.g. a new order). The invoice PDF is attached when $invoicePdfPath is given.

Parameters
$order : Order
$status : OrderStatus
$invoicePdfPath : string|null
$invoiceVariableSymbol : string|null = null
Return values
PreparedOrderEmail|null

prepareVoucherEmail()

Renders the system template `ES_NEW_VOUCHER` (compensation voucher from {@see VoucherGenerator}).

public prepareVoucherEmail(Order $order, Voucher $voucher, array{voucherLevelId: int, durationDays: int, minPrice: string, maxPrice: string, percents: int, fixedAmount: ?string} $level, string $orderTotal) : PreparedOrderEmail|null

Values: voucher.code/percents/price/endDate/minPrice/maxPrice and currency.shortcut. For a percentage band price is only an informative percents % of $orderTotal; the redemption itself is always percentage-based. For a fixed-amount band (getHasPercents() is false) price is level['fixedAmount'], the real voucher value.

Parameters
$order : Order
$voucher : Voucher
$level : array{voucherLevelId: int, durationDays: int, minPrice: string, maxPrice: string, percents: int, fixedAmount: ?string}
$orderTotal : string
Return values
PreparedOrderEmail|null

recapValues()

Builds the variables of the order e-mail templates.

public recapValues(TOrderGraph $order[, string|null $invoiceVariableSymbol = null ]) : array<string, mixed>

The templates live in the database (order_status_texts.email_body, email_texts.body) and read these values through Latte expressions. Amounts arrive already formatted in the order currency (filter priceFormat); the template only prints them.

  • $order: orderNumber, variableSymbol, totalPriceWithVat (the payable rounded amount), itemsTotal, rounding (only when roundingLine), roundingLine, withVat, totalBase, note
  • $items: name, code, quantity, unit, unitPrice, totalPrice, fees (text informative only: already included in the price, not added)
  • $shipping / $payment: name, price (or null); $payment.isTransfer
  • $vouchers: code, discount (positive discount amount)
  • $gifts: name, amount (gifts of the order, free of charge)
  • $vatRecap: rate, base, vat, total (empty for an order without VAT)
  • $order.taxNote: VAT clause in the order language and Czech; an empty string means the treatment has no clause (domestic supply by a VAT payer)
  • $bank: account, iban, swift, bankName, variableSymbol, amount, missing (missing is a transfer without a seller account; the template must say so instead of leaving a blank)

Values include VAT (the paid amounts) for an order with VAT; for a non-payer *WithVat equals the base.

Parameters
$order : TOrderGraph
$invoiceVariableSymbol : string|null = null

variable symbol of the issued invoice (a transfer is matched by it)

Return values
array<string, mixed>

adminEmail()

Seller e-mail of the order, falling back to the site mailbox `1/email.address`; `null` when neither is valid.

private adminEmail(Order $order) : string|null
Parameters
$order : Order
Return values
string|null

formatMoney()

private formatMoney(string|float|null $amount, object|null $currency) : string
Parameters
$amount : string|float|null
$currency : object|null
Return values
string

inOrderFormat()

Runs the render in the localization and language of the order. An order without localization (historical) falls back to the request localization.

private inOrderFormat(TOrderGraph $order, callable(): Array $render) : PreparedOrderEmail|null
Parameters
$order : TOrderGraph
$render : callable(): Array
Return values
PreparedOrderEmail|null

isTransferPayment()

Tells whether the payment is a bank transfer: the method sends a proforma invoice and has no payment gateway (same rule as `OrderCheckoutManager::targetStatusKey()`).

private isTransferPayment(object|null $orderPaymentMethod) : bool

The OrderPaymentMethod snapshot carries only name and price, so the method properties are read from the catalog entity (lazy). A failed read means "not a transfer": the e-mail then simply omits the payment details.

Parameters
$orderPaymentMethod : object|null
Return values
bool

orderLocalization()

Returns the order localization (snapshot from checkout/admin).

private orderLocalization(TOrderGraph $order) : object|null

A lazy proxy detached after UoW::clear() may not initialize; the result is then null and the request format is used, so the e-mail does not fail.

Parameters
$order : TOrderGraph
Return values
object|null

render()

Renders subject and body; a failed render (see {@see renderTemplate()}) returns `null`, so no empty e-mail is queued.

private render(string $subject, string $body, string $to, array<string, mixed> $values, array<int, array{fileName: string, filePath: string, contentType: ?string}> $files, bool $preferred) : PreparedOrderEmail|null
Parameters
$subject : string
$body : string
$to : string
$values : array<string, mixed>
$files : array<int, array{fileName: string, filePath: string, contentType: ?string}>
$preferred : bool
Return values
PreparedOrderEmail|null

renderSubject()

Renders the subject as a Latte string (no wrapper template).

private renderSubject(string $subject, array<string, mixed> $values) : string

The output is plain text: HTML entities from escaping are decoded and tags stripped. A render error returns the subject as written in the template (the e-mail is not dropped because of its subject) and is logged to eshop.general.

Parameters
$subject : string
$values : array<string, mixed>
Return values
string

renderTemplate()

Renders the e-mail, returning `null` on failure.

private renderTemplate(string $body, array<string, mixed> $values) : string|null

IMPORTANT: a failed render (broken Latte template, unwritable tempDir, missing email.latte) must neither break the transition nor produce an empty e-mail. It catches \Throwable, not just \Exception: an \Error from a broken template or helper would otherwise abort the final transaction. The failure is logged to eshop.general and prepare*() returns null, so nothing is queued.

Parameters
$body : string
$values : array<string, mixed>
Return values
string|null

resolveLanguageId()

Returns `order.language`, falling back to the site-wide default language.

private resolveLanguageId(Order $order) : int
Parameters
$order : Order
Return values
int
On this page

Search results