| @@ -32,8 +32,10 @@ | ||
| 32 | 32 | isCoreFree: boolean; |
| 33 | 33 | /** If set, subject/body cannot be edited until Pro + this module slug is active (row still listed). */ |
| 34 | 34 | requiresModule?: string; |
| 35 | 35 | settingsFlag?: keyof EmailSettingsValues; |
| 36 | + /** Only relevant when deposits / partial payments are enabled. */ | |
| 37 | + requiresPartialPayments?: boolean; | |
| 36 | 38 | settingsSubject?: keyof EmailSettingsValues; |
| 37 | 39 | settingsBody?: keyof EmailSettingsValues; |
| 38 | 40 | /** Shown in core editor sidebar for merge tags */ |
| 39 | 41 | mergeTags?: string; |
| @@ -41,12 +43,16 @@ | ||
| 41 | 43 | |
| 42 | 44 | export const CORE_FREE_TEMPLATE_KEYS = [ |
| 43 | 45 | "booking_confirmation", |
| 44 | 46 | "payment_received", |
| 47 | + "partial_payment_received", | |
| 45 | 48 | "booking_cancelled", |
| 46 | 49 | "trip_reminder", |
| 47 | 50 | "trip_consent_request", |
| 48 | 51 | "customer_email_verification", |
| 52 | + "guest_email_verification", | |
| 53 | + "account_email_change_request", | |
| 54 | + "account_email_changed", | |
| 49 | 55 | "booking_completed", |
| 50 | 56 | "booking_expired_customer", |
| 51 | 57 | "admin_booking_expired", |
| 52 | 58 | "scheduled_payment_reminder", |
| @@ -111,8 +117,29 @@ | ||
| 111 | 117 | "{{site_name}}, {{customer_name}}, {{customer_first_name}}, {{booking_reference}}, {{trip_name}}, {{travel_date}}, {{payment_amount_formatted}}, {{payment_method}}, {{transaction_id}}, {{total_amount_formatted}}, {{currency}}, " + |
| 112 | 118 | BOOKING_RICH_MERGE_TAGS, |
| 113 | 119 | }, |
| 114 | 120 | { |
| 121 | + template_key: "partial_payment_received", | |
| 122 | + event_key: "payment.partial_received", | |
| 123 | + name: __("Partial Payment Received", "yatra"), | |
| 124 | + description: __( | |
| 125 | + "Sent when a payment is recorded but a balance is still outstanding. Only used when deposits or partial payments are enabled and this template is switched on — otherwise the standard Payment Received email is sent for every payment.", | |
| 126 | + "yatra", | |
| 127 | + ), | |
| 128 | + category: "payment", | |
| 129 | + recipient_type: "customer", | |
| 130 | + to_email: "{customer_email}", | |
| 131 | + isCoreFree: true, | |
| 132 | + // Shown only when the site actually takes deposits / partial payments. | |
| 133 | + requiresPartialPayments: true, | |
| 134 | + settingsFlag: "email_template_partial_payment", | |
| 135 | + settingsSubject: "email_tpl_partial_payment_subject", | |
| 136 | + settingsBody: "email_tpl_partial_payment_body", | |
| 137 | + mergeTags: | |
| 138 | + "{{site_name}}, {{customer_name}}, {{customer_first_name}}, {{booking_reference}}, {{trip_name}}, {{travel_date}}, {{payment_amount_formatted}}, {{amount_paid_formatted}}, {{amount_due_formatted}}, {{total_amount_formatted}}, {{payment_method}}, {{transaction_id}}, {{currency}}, " + | |
| 139 | + BOOKING_RICH_MERGE_TAGS, | |
| 140 | + }, | |
| 141 | + { | |
| 115 | 142 | template_key: "booking_cancelled", |
| 116 | 143 | event_key: "booking.cancelled", |
| 117 | 144 | name: __("Booking Cancellation", "yatra"), |
| 118 | 145 | description: __("Sent when a booking is marked cancelled.", "yatra"), |
| @@ -183,8 +210,62 @@ | ||
| 183 | 210 | mergeTags: |
| 184 | 211 | "{{site_name}}, {{site_url}}, {{customer_first_name}}, {{customer_name}}, {{verification_link}}, {{intro_paragraph}}, {{expiry_notice_html}}, {{footer_note}}", |
| 185 | 212 | }, |
| 186 | 213 | { |
| 214 | + template_key: "guest_email_verification", | |
| 215 | + event_key: "account.email_verification", | |
| 216 | + name: __("Guest email verification (checkout)", "yatra"), | |
| 217 | + description: __( | |
| 218 | + "Sent to a guest at checkout who must verify their email before the booking is finalized (when 'Require guest email verification' is enabled). Distinct from the account-registration verification above.", | |
| 219 | + "yatra", | |
| 220 | + ), | |
| 221 | + category: "account", | |
| 222 | + recipient_type: "customer", | |
| 223 | + to_email: "{customer_email}", | |
| 224 | + isCoreFree: true, | |
| 225 | + settingsFlag: "email_template_guest_verification", | |
| 226 | + settingsSubject: "email_tpl_guest_verification_subject", | |
| 227 | + settingsBody: "email_tpl_guest_verification_body", | |
| 228 | + mergeTags: | |
| 229 | + "{{site_name}}, {{site_url}}, {{customer_first_name}}, {{customer_name}}, {{verification_link}}, {{intro_paragraph}}, {{expiry_notice_html}}, {{footer_note}}", | |
| 230 | + }, | |
| 231 | + { | |
| 232 | + template_key: "account_email_change_request", | |
| 233 | + event_key: "account.email_change_request", | |
| 234 | + name: __("Account email change request", "yatra"), | |
| 235 | + description: __( | |
| 236 | + "Sent to the NEW address when a customer changes their account email. Contains the confirmation link; the change only applies once they click it.", | |
| 237 | + "yatra", | |
| 238 | + ), | |
| 239 | + category: "account", | |
| 240 | + recipient_type: "customer", | |
| 241 | + to_email: "{new_email}", | |
| 242 | + isCoreFree: true, | |
| 243 | + settingsFlag: "email_template_account_email_change", | |
| 244 | + settingsSubject: "email_tpl_account_email_change_subject", | |
| 245 | + settingsBody: "email_tpl_account_email_change_body", | |
| 246 | + mergeTags: | |
| 247 | + "{{site_name}}, {{site_url}}, {{customer_first_name}}, {{customer_name}}, {{new_email}}, {{verification_link}}, {{intro_paragraph}}, {{footer_note}}", | |
| 248 | + }, | |
| 249 | + { | |
| 250 | + template_key: "account_email_changed", | |
| 251 | + event_key: "account.email_changed", | |
| 252 | + name: __("Account email changed", "yatra"), | |
| 253 | + description: __( | |
| 254 | + "Security notice sent to the OLD address once a customer's account email change is confirmed.", | |
| 255 | + "yatra", | |
| 256 | + ), | |
| 257 | + category: "account", | |
| 258 | + recipient_type: "customer", | |
| 259 | + to_email: "{customer_email}", | |
| 260 | + isCoreFree: true, | |
| 261 | + settingsFlag: "email_template_account_email_changed", | |
| 262 | + settingsSubject: "email_tpl_account_email_changed_subject", | |
| 263 | + settingsBody: "email_tpl_account_email_changed_body", | |
| 264 | + mergeTags: | |
| 265 | + "{{site_name}}, {{site_url}}, {{customer_first_name}}, {{customer_name}}, {{new_email}}, {{intro_paragraph}}, {{footer_note}}", | |
| 266 | + }, | |
| 267 | + { | |
| 187 | 268 | template_key: "admin_new_booking", |
| 188 | 269 | event_key: "booking.created", |
| 189 | 270 | name: __("Admin: New Booking", "yatra"), |
| 190 | 271 | description: __( |
| @@ -616,8 +697,21 @@ | ||
| 616 | 697 | is_locked: boolean; |
| 617 | 698 | variables: string[]; |
| 618 | 699 | created_at?: string; |
| 619 | 700 | updated_at?: string; |
| 701 | + /** | |
| 702 | + * Pro Email Automation trip-specific overrides. `overrides` is the global | |
| 703 | + * template's key when this row is an override ("" otherwise); `targets` | |
| 704 | + * says which trips it applies to; `priority` orders overrides of the same | |
| 705 | + * global template; `effective_event_key` is the event the row fires on | |
| 706 | + * (an override's own event_key is stored empty). | |
| 707 | + */ | |
| 708 | + overrides?: string; | |
| 709 | + /** True when this global template may have trip-specific overrides. */ | |
| 710 | + overridable?: boolean; | |
| 711 | + targets?: { trips?: number[]; categories?: number[]; trip_types?: string[] }; | |
| 712 | + priority?: number; | |
| 713 | + effective_event_key?: string; | |
| 620 | 714 | }; |
| 621 | 715 | |
| 622 | 716 | export type BuildLocalTemplateRowsOptions = { |
| 623 | 717 | isProPluginActive: boolean; |
| @@ -631,9 +725,17 @@ | ||
| 631 | 725 | const pro = options?.isProPluginActive ?? false; |
| 632 | 726 | const moduleOk = (slug: string) => |
| 633 | 727 | options?.isModuleActive ? options.isModuleActive(slug) : false; |
| 634 | 728 | |
| 635 | - return EMAIL_TEMPLATES_CATALOG.map((entry) => { | |
| 729 | + // Sites that never take a deposit or part payment have no use for the | |
| 730 | + // part-payment template, so it is hidden rather than shown inert. | |
| 731 | + const partialPaymentsOn = Boolean( | |
| 732 | + values.partial_payment || values.enable_deposit || values.deposit_required, | |
| 733 | + ); | |
| 734 | + | |
| 735 | + return EMAIL_TEMPLATES_CATALOG.filter( | |
| 736 | + (entry) => !entry.requiresPartialPayments || partialPaymentsOn, | |
| 737 | + ).map((entry) => { | |
| 636 | 738 | const moduleGateOk = |
| 637 | 739 | !entry.requiresModule || (pro && moduleOk(entry.requiresModule)); |
| 638 | 740 | |
| 639 | 741 | const proCatalogLocked = !entry.isCoreFree; |