Email workspaceInsurance purchase details — provider
Source: App\Mail\InsuranceOrderConfirmed, app/Mail/InsuranceOrderConfirmed.php; resources/views/emails/insurance/purchase.blade.php using mail::message. Subject: New Insurance Purchase From Built! (unchanged). Suggested preheader: Insurance purchase details for {{product_name}}.
Common portable values
| Token | Existing source | Handling |
|---|---|---|
| {{provider_name}} | provider.name ?? '', where provider = order.serviceProvider | Optional escaped provider greeting, omitted as a whole if empty/null; do not invent another recipient. |
| {{product_name}} | order.product.name | Required original product display. |
| {{insured_name}} | order.name | Required named insured person, distinct from the purchaser and beneficiary. |
| {{purchase_amount}} | order.currency . ' ' . order.amount | Required **raw** original display with a space; no number_format, comma insertion or fixed two decimals. Do not substitute receipt formatting. |
| {{purchased_by}} | order.user?->first_name ?? 'N/A' | Required row. Null user/name becomes N/A; empty string/0 remain. The separately bound user variable does not override this source expression. |
| {{product_type_name}} | order.product.type->name() | Required native enum display (Life Insurance / Motor Vehicle Insurance); do not infer from product text. |
| {{insured_phone}} | order.phone_number | Required original order phone, not buyer/provider/beneficiary phone. |
| {{app_name}} | config('app.name') | Original Thanks sign-off. |
| {{preheader}} | Product summary above | Escaped text, no underwriting/coverage guarantee. |
Default logo/optional {{logo_url}} and shared badge CID/HTTPS policy: [shared-footer](../shared-footer.md).
Motor repeat contract
Original condition is strict enum identity: order.product.type === App\Enums\InsuranceTypes::MotorVehicleInsurance. Preserve the source enum/cast, not a loose guessed product-name test. Preview product_type_key is an adapter discriminator derived from that enum; it is not a printed token.
For every order.data entry, map {{motor_field_label}} to Str::headline(original key) and {{motor_field_value}} to its original scalar display (null to empty, 0 to 0). Preserve order and every entry: there is **no row cap**. The ready table marks one repeat row; native integration must foreach the original collection and escape label/value separately. No arbitrary HTML-row placeholder or untrusted raw HTML is accepted. Empty data renders no motor rows/caption/table; source motor creation normally requires cover_type, vehicle_registration_number and vehicle_classification. Empty/twelve-field fixtures test source-view behavior, not new creation rules. If stored values are nested/non-scalar, the original Blade is not a defined JSON renderer; make an explicit adapter/error-handling decision rather than silently serializing or dropping them.
Life and beneficiary values
Retain this whole section only when order.product.type === App\Enums\InsuranceTypes::LifeInsurance. All rows are unconditional inside that branch, including empty/0 values. Remove it completely for motor insurance and remove motor content for life insurance.
| Token | Existing source |
|---|---|
| {{birth_date}} | order.birth_date, original display; no new date conversion |
| {{age}} | order.age, supplied stored age; do not recalculate at send time |
| {{gender}} | order.gender |
| {{address}} | order.address |
| {{nationality}} | order.nationality?->name; null remains empty, not N/A |
| {{marital_status}} | order.marital_status |
| {{occupation}} | order.occupation |
| {{beneficiary_name}} | order.beneficiary_name |
| {{beneficiary_phone}} | order.beneficiary_phone_number |
| {{beneficiary_birth_date}} | order.beneficiary_birth_date, original display |
| {{beneficiary_age}} | order.beneficiary_age, no new calculation |
| {{beneficiary_relationship}} | order.beneficiary_relationship |
| {{beneficiary_gender}} | order.beneficiary_gender |
Escape all fields as text; preserve the buyer/insured/beneficiary distinction. Missing mandatory model/product/enum context needs an explicit target-project decision. Do not introduce ID documents, bank details, policy dates, nationality-file URLs, claim information or other personal fields absent from this email. All demographic/vehicle samples here are fictional.
Trigger and delivery
InsuranceOrderController::changeState (:216–295) updates order/activity in a transaction. For status confirmed it validates a truthy serviceProvider.business_email with FILTER_VALIDATE_EMAIL, then queues this Mailable to that provider with existing internal BCC at :238. build() binds provider/order/user. The same operation queues a separate customer status update after the transaction. Preserve those audiences, ordering, route/authentication and status guards. Route POST insurance-orders/{id}/change-status: routes/api.php:224. The public changeStatus path restricts allowed transitions; do not add a confirmed-again send or different eligibility rule through HTML.
No explicit From/Reply-To override, PDF, email attachment or workflow URL exists. Keep native subject, queue(), To/BCC and transport/outbox policy. Confirmed-order provider purchase details do not independently prove that a NewInsurancePolicy has already been issued; policy creation is the separate completed branch. Product/identity files stored in models are not attached here.
Native integration and safety
Use the existing Mailable with a complete HTML Blade view, native enum condition/foreach and proposed plain-text alternative. Portable {{placeholder_name}} tokens are not automatically Blade; no new framework is required. Remove unselected branch wrappers in HTML/text and repeat all motor rows. Escape text/attributes, validate images separately and use one pass if replacing tokens. CID assets must actually be embedded or replaced with approved HTTPS assets. There are no legacy duplicate action-link fields because none is supplied.
Seven states cover motor/life, original null/empty fallbacks, supplied zero/ages as rendering-only checks, empty motor iterable, twelve motor rows and long life details. New creation validation does not necessarily accept each robustness fixture. Files: public/ready/insurance-provider-purchase.html/.txt and previews/insurance-provider-purchase-*.html/.txt. No separate per-email project-owned text source found. Browser checks do not verify real personal data, coverage/payment, actual Gmail/Outlook/iOS Mail/CID behavior or current production sending.