Appearance
Order Status Email Notifications
Flow ID: SY-02 | Module(s): job, eshop | Complexity: Medium Last Updated: 2026-04-04
Business Overview
When an order transitions to INVOICED or SENT status, the platform automatically notifies the customer via email. For shipped orders, an SMS notification is also dispatched through a configurable provider. There are three distinct notification paths depending on the fulfillment model:
- Invoiced orders (warehouse dispatch) -- email only, triggered when the order reaches INVOICED status.
- Shipped orders (courier delivery) -- email plus SMS, triggered when the order reaches SENT status with a courier assigned.
- Store-pickup orders -- email plus SMS, triggered when the order reaches SENT status at a physical store location.
All three jobs are per-client opt-in (commented out by default in jobs.php) because not every merchant uses the same notification strategy.
Architecture
AdvSendEmailBasedOnSentStatus (email on INVOICED)
AdvSendEmailAndSMSBasedOnSentStatus (email+SMS on SENT, courier)
AdvSendEmailAndSMSBasedOnFromStoreStatus (email+SMS on SENT, store pickup)
|
+--> order_model::getRecords() query eligible orders
+--> adv_mailer::order_has_been_updated() / order_is_on_store()
+--> sendSmsForOrder() / sendSmsForOrderId() (SMS helpers)
+--> order_model::update_order() mark is_email_sent = trueEach job class lives in ecommercen/job/libraries/ and has a thin client-overridable subclass in application/modules/job/libraries/.
Job Classes
| Class | File | Status Trigger | Channels |
|---|---|---|---|
AdvSendEmailBasedOnSentStatus | ecommercen/job/libraries/AdvSendEmailBasedOnSentStatus.php | INVOICED | |
AdvSendEmailAndSMSBasedOnSentStatus | ecommercen/job/libraries/AdvSendEmailAndSMSBasedOnSentStatus.php | SENT (courier) | Email + SMS |
AdvSendEmailAndSMSBasedOnFromStoreStatus | ecommercen/job/libraries/AdvSendEmailAndSMSBasedOnFromStoreStatus.php | SENT (store) | Email + SMS |
Client Overridable Classes
| Class | File |
|---|---|
SendEmailBasedOnSentStatus | application/modules/job/libraries/SendEmailBasedOnSentStatus.php |
SendEmailAndSMSBasedOnSentStatus | application/modules/job/libraries/SendEmailAndSMSBasedOnSentStatus.php |
SendEmailAndSMSBasedOnFromStoreStatus | application/modules/job/libraries/SendEmailAndSMSBasedOnFromStoreStatus.php |
Code Flow
SY-02a: AdvSendEmailBasedOnSentStatus (Invoiced Orders)
- Query eligible orders via
order_model->getRecords()with conditions:is_email_sent = falsestatus = 'INVOICED'store_id IS NULL(excludes store-pickup orders)gtcode != ''(must have a tax document code)
- For each order, send email via
adv_mailer->order_has_been_updated($orderId, $data):- Loads order + customer data
- Builds encrypted order tracking link
- Resolves transporter info for courier display
- Sends via the
orderUpdateemail template with subject fromEMAIL_SUBJECTS.ORDER_UPDATEregistry - Attaches invoice PDF if available (for INVOICED/SENT/PAID_SENT statuses)
- Mark processed: sets
is_email_sent = trueon the order record.
SY-02b: AdvSendEmailAndSMSBasedOnSentStatus (Shipped Orders)
- Validate options: requires
provideroption (SMS provider name). Exits silently if missing. - Query eligible orders with conditions:
is_email_sent = falsestatus = 'SENT'store_id IS NULL(courier delivery only)gtcode IS NOT NULL AND gtcode != ''transport_id IS NOT NULL(courier must be assigned)
- For each order:
- Send email via
adv_mailer->order_has_been_updated() - If
sms_status == 1(SMS pending), dispatch SMS viasendSmsForOrder():- Resolves transporter from cache
- Dispatches through the configured provider
- Updates
sms_statusbased on provider response (see SMS status codes below)
- Sets
is_email_sent = true
- Send email via
SY-02c: AdvSendEmailAndSMSBasedOnFromStoreStatus (Store Pickup)
- Validate options: requires
provideroption. - Query eligible orders with conditions:
is_email_sent = falsestatus = 'SENT'store_id IS NOT NULL(store-pickup only)sent_date_time <= today 17:00:00(only notify after the cutoff time)
- For each order:
- Send email via
adv_mailer->order_is_on_store():- Loads store details for the pickup location
- Uses
orderOnStoreemail template - Subject from
EMAIL_SUBJECTS.ORDER_ON_STOREregistry
- If
sms_status == 1, dispatch SMS viasendSmsForOrderId()(simpler variant without transporter) - Sets
is_email_sent = true
- Send email via
Data Model
Primary Table: shop_order
| Column | Type | Role |
|---|---|---|
id | int | PK |
order_serial | varchar | Human-readable order number |
status | varchar | Order status (PENDING, PAID, INVOICED, SENT, etc.) |
is_email_sent | boolean | Flag -- set to true after notification sent |
sms_status | int | SMS delivery state (see below) |
store_id | int/null | NULL = courier delivery; non-null = store pickup |
transport_id | int/null | FK to transporter/courier |
gtcode | varchar | Tax document code (invoice number) |
sent_date_time | datetime | When the order was marked as shipped |
customer_id | int | FK to customer |
invoice_pdf | varchar | Filename of generated invoice PDF |
SMS Status Codes
| Value | Meaning |
|---|---|
| 1 | Pending (customer opted in, SMS not yet sent) |
| 2 | Sent successfully (Plivo) |
| 3 | Failed to send |
| 4 | Sent successfully (Bulker/Yuboto Omni/Omni Messaging) |
| other | Provider-specific callback status (Yuboto, Routee) |
Configuration
Job Scheduling (application/config/jobs.php)
All three jobs are commented out by default (per-client opt-in):
php
// ['command' => 'SendEmailBasedOnSentStatus', 'schedule' => '0 21 * * *', 'graceTime' => 300, 'retryTimes' => 3],
// ['command' => 'SendEmailAndSMSBasedOnSentStatus', 'schedule' => '0 21 * * *', 'graceTime' => 300, 'retryTimes' => 3, 'options' => ['provider' => 'yuboto']],
// ['command' => 'SendEmailAndSMSBasedOnFromStoreStatus', 'schedule' => '0 21 * * *', 'graceTime' => 300, 'retryTimes' => 3, 'options' => ['provider' => 'yuboto']],Default schedule: daily at 21:00. Queue: core.
SMS Providers
The provider option accepts one of:
| Provider | Callback | Status on success |
|---|---|---|
yuboto | webrun/yuboto_callback/{orderId} | Callback-driven |
yuboto_omni | webrun/yubotoOmniCallback/{orderId} | 4 |
routee | webrun/routee_callback/{orderId} | Callback-driven |
routeeViber | webrun/routee_callback_viber/{orderId} | Callback-driven |
plivo | None | 2 |
bulker | None | 4 |
omni_messaging | None | 4 |
Registry Settings
| Group | Key | Purpose |
|---|---|---|
EMAIL_SUBJECTS | ORDER_UPDATE | Email subject template (supports %s for order serial) |
EMAIL_SUBJECTS | ORDER_ON_STORE | Store-pickup email subject template |
COMPANY_PHONE | ESHOP | Company phone included in email body |
Email Templates
| Template key | Used by |
|---|---|
orderUpdate | INVOICED and SENT notifications |
orderOnStore | Store-pickup notifications |
SMTP Configuration
Both email methods use the EMAIL_SHOP_MAILER SMTP profile.
Client Extension Points
Override the job class: Create a class in
application/modules/job/libraries/extending theAdv*base class. OverridegetQueryOptions()to change which orders are selected, or overrideexecuteCommand()to add custom logic.Override the mailer: Extend
Adv_mailerinapplication/models/to customize email content or add additional recipients.Override email templates: Place custom email view files in
application/views/to override the defaultorderUpdateandorderOnStorelayouts.Change SMS provider: Set the
options.providervalue injobs.phpto switch between supported SMS gateways.Adjust schedule: Uncomment and modify the cron expression in
jobs.phpto match the client's business hours.
Business Rules
| Rule | Description |
|---|---|
| One-shot delivery | Each order is notified exactly once; is_email_sent flag prevents re-processing |
| Store cutoff time | Store-pickup notifications are only sent for orders shipped before 17:00 on the current day |
| SMS opt-in | SMS is only sent when sms_status == 1 (customer consented) |
| Tax code required | INVOICED and SENT notifications require a non-empty gtcode |
| Courier required | SENT (courier) notifications require a non-null transport_id |
| Invoice attachment | PDF invoice is attached to the email when available for INVOICED/SENT/PAID_SENT statuses |
| Per-client activation | Jobs are commented out by default; merchants enable the ones matching their fulfillment model |
Related Flows
- SY-01 Cron Job Framework -- job scheduling and execution
- SY-24 Email Dispatch System --
Adv_mailerinternals, SMTP routing, and template rendering used by all notifications in this flow - AD-03 Order Management -- status transitions that trigger these jobs
- AD-33 Multi-Carrier Tracking -- courier tracking after shipment
- IN-14 SMS Integrations -- SMS provider details for the SMS notification channel