Skip to content

Waiting List Notifications

Flow ID: SY-13 | Module(s): job, eshop, Product domain | Complexity: Low Last Updated: 2026-04-04

Business Overview

When customers subscribe to out-of-stock products via the storefront waiting list, the system stores their email and product reference. A daily cron job checks whether subscribed products have returned to stock, then sends grouped email notifications to each customer listing all their now-available products. This converts interest signals into purchase opportunities without manual intervention.

What the job does:

  • Scans the shop_waiting_list table for unsent entries where the product is active and in stock
  • Groups available products by customer email to send one consolidated email per customer
  • Sends the notification email using the waitingListSuccess template
  • Marks all processed entries as sent with a timestamp

Business value: Recovers lost sales from out-of-stock situations by automatically re-engaging interested customers the moment inventory is restored.


Architecture

AdvSendEmailForWaitingList (JobCommand)
  |
  +--> waiting_list_model::getRecordsToSendEmails($lang)
  |       joins: shop_waiting_list + shop_product + product_codes + shop_product_mui + shop_vendor + shop_vendor_mui
  |       filters: waiting_status=0, product active=1, stock>0 OR negative_stock=1
  |
  +--> Group records by customer email
  |
  +--> adv_mailer::sendEmailForWaitingList($email, $data, $lang)
  |       template: waitingListSuccess
  |       subject: registry EMAIL_SUBJECTS.WAITING_LIST
  |
  +--> waiting_list_model::markAsSent($ids)
         sets waiting_status=1, email_sent_date=now

Job Classes

ClassFilePurpose
AdvSendEmailForWaitingListecommercen/job/libraries/AdvSendEmailForWaitingList.phpBase job implementation
SendEmailForWaitingListapplication/modules/job/libraries/SendEmailForWaitingList.phpClient-overridable subclass

Supporting Classes

ClassFileRole
Adv_waiting_list_modelecommercen/eshop/models/Adv_waiting_list_model.phpLegacy model with query logic
Waiting_list_modelapplication/modules/eshop/models/Waiting_list_model.phpClient-overridable model
Adv_mailerapplication/models/Adv_mailer.phpEmail dispatch
Entitysrc/Domains/Product/WaitingList/Repository/Entity.phpModern domain entity
Repositorysrc/Domains/Product/WaitingList/Repository/Repository.phpModern domain repository
WriteRepositorysrc/Domains/Product/WaitingList/Repository/WriteRepository.phpWrite operations

Code Flow

1. Job Initialization

The job loads the waiting list model, mailer, and refreshes the registry to get live configuration:

constructor:
  load waiting_list_model
  load adv_mailer
  registry->live()  (refresh from DB for latest config)

2. Query Eligible Records

getRecordsToSendEmails($lang) builds a multi-table join:

  1. Base table: shop_waiting_list where waiting_status = 0 (not yet notified)
  2. Product check: joins shop_product where active = 1
  3. Stock check: joins product_codes where stock > 0 OR product allows negative_stock = 1
  4. Language filter: matches the lang column on the waiting list entry, product MUI, and vendor MUI
  5. Data enrichment: selects product name, slug, vendor slug, and admin thumbnail image
  6. Grouping: GROUP BY shop_product.id to deduplicate product codes per product
  7. Ordering: by email ASC, then creation_date ASC

3. Group by Customer

The job iterates results and groups them by email address so each customer receives a single email listing all their available products.

4. Send Notifications

For each customer email, calls adv_mailer->sendEmailForWaitingList():

  • Builds a customer data object with mail, lang, and id=null (no customer account required)
  • Uses the waitingListSuccess email template
  • Subject line from registry: EMAIL_SUBJECTS.WAITING_LIST
  • SMTP profile: EMAIL_SHOP_MAILER

5. Mark as Sent

After all emails are dispatched, calls markAsSent($ids) with all processed record IDs:

  • Sets waiting_status = 1
  • Sets email_sent_date to current datetime

Data Model

Primary Table: shop_waiting_list

ColumnTypeRole
idintPK, auto-increment
emailvarcharCustomer email address
langvarcharLanguage code (e.g., el, en)
product_idintFK to shop_product.id
creation_datedatetimeWhen the subscription was created
waiting_statusint0 = waiting, 1 = notified, 2 = deleted/canceled
email_sent_datedatetime/nullWhen notification was sent
TableRelationshipPurpose
shop_productproduct_id -> idProduct active status and negative_stock flag
product_codesproduct_id -> product_idStock quantity check
shop_product_muiproduct_id -> product_idProduct name and slug (language-specific)
shop_vendorvendor_id -> id (via product)Vendor lookup
shop_vendor_muivendor_id -> vendor_idVendor slug (language-specific)

Waiting Status Values

ValueMeaning
0Waiting (not yet notified)
1Notified (email sent)
2Deleted/canceled by admin

Configuration

Job Scheduling (application/config/jobs.php)

php
['command' => 'SendEmailForWaitingList', 'schedule' => '0 11 * * *', 'graceTime' => 300, 'retryTimes' => 3, 'options' => ['lang' => 'el']],

Default schedule: daily at 11:00. The lang option scopes notifications to a specific language. For multi-language sites, multiple job entries may be configured with different lang values.

Job Options

OptionTypeRequiredDescription
langstringNoLanguage abbreviation to filter notifications. Defaults to site's language_abbr config

Registry Settings

GroupKeyPurpose
EMAIL_SUBJECTSWAITING_LISTEmail subject line for waiting list notifications
EMAIL_SHOP_MAILER(group)SMTP configuration for outbound shop emails

Email Templates

Template keyDescription
waitingListSuccessEmail body listing products that are back in stock, with links

Client Extension Points

  1. Override the job class: Create SendEmailForWaitingList in application/modules/job/libraries/ extending AdvSendEmailForWaitingList. Override executeCommand() to add custom logic (e.g., additional filters, custom grouping).

  2. Override the model: Create Waiting_list_model in application/modules/eshop/models/ extending Adv_waiting_list_model. Override getRecordsToSendEmails() to change the stock-check query (e.g., add minimum stock threshold).

  3. Override the mailer: Extend Adv_mailer in application/models/ to customize the email content, add CC recipients, or change the template.

  4. Override email template: Place a custom waitingListSuccess view file in application/views/ to change the email layout.

  5. Multi-language scheduling: Add multiple job entries in jobs.php with different lang options to send notifications per language at different times.


Business Rules

RuleDescription
Stock-or-negativeProducts qualify when product_codes.stock > 0 OR shop_product.negative_stock = 1
Active products onlyOnly active products (active = 1) trigger notifications
Language scopingNotifications are filtered by language, matching the waiting list entry's lang field
One notification per entryEach shop_waiting_list row is sent exactly once; waiting_status flag prevents reprocessing
Grouped per customerMultiple products for the same email are consolidated into a single email
No account requiredWaiting list uses email-only identification; no customer account is needed
Duplicate preventionThe isInWaitingList() check prevents duplicate subscriptions (same email + product + status=0)