Email workspaceTier 3 report contract
Implementation: App\Mail\tier3, app/Mail/tier3.php. Original Markdown view: resources/views/emails/payroll/tier3.blade.php using mail::message. Route: routes/api.php, POST sendtier3/{id}. Caller: app/Http/Controllers/General/emailsController.php:504, sendtier3(). Static references are usage evidence, not production-delivery proof.
Suggested subject: Tier3 Social Security contributions for {{pay_period}}. Retain the existing exact header pattern; braces around the Mailable source description above are explanatory, not portable tokens.
Suggested preheader: {{company_name}}: report PDF for {{pay_period}}.
Placeholder contract
| Token | Existing source / derivation | Handling |
|---|---|---|
| {{logo_url}} | Approved original Built app_name PNG | Optional deployment override; concrete approved HTTPS image is already present in ready HTML. Use approved absolute HTTPS or a matching attached CID. |
| {{preheader}} | Suggested existing company/month summary above | Required escaped text; no filing, remittance or delivery guarantee. |
| {{company_name}} | $data[payroll_settings]->Company_name | Required escaped employer identity; not the recipient. The loaded Mailable payroll settings use PayrollSettings::where(business_id, payrun.business_id)->first(). |
| {{pay_period}} | date('F, Y', strtotime($payrun->run_date)) | Required existing formatted reporting month; retain source formatting/timezone semantics. It is not a deadline, submission date or payment date. |
| {{business_address}} | $data[business]->address | Optional escaped text. Omit the entire Address row if absent; preserve supplied line breaks. |
| {{business_phone}} | $data[business]->phone_number | Optional escaped text, not a number. Omit the entire Tel row if absent; retain leading + and zeroes. No new tel: action. |
| {{app_name}} | config(app.name) in the original view | Required escaped application sign-off; preserve separately from payroll_settings.Company_name. The fictional default is Built. |
Sign-off source remains config(app.name). No recipient name, total, employee count, rate, payment status or statutory deadline exists in the original body; none is added.
Recipient, trigger and queue
The controller validates request.email with required|email:dns, loads Payrun::find(id), and explicitly calls Mail::to(request.email)->queue(new tier3(payrun)). This is a user/request-selected report recipient, not necessarily an employee, owner or statutory authority. Keep the existing route’s authorization and request handling in the consuming application; this design adds none. Queueable/SerializesModels alone do not prove queuing; the explicit queue() caller is the evidence. Do not change it to send() or alter recipients/CC/BCC.
The Mailable loads all PayRunIitem rows by payrun_id and the business by payrun.business_id, with payroll settings and business-owner lookup. Preserve those existing data/attachment dependencies; no payroll records or calculations are moved into the email.
Headers and attachment contract
Reply-To is business.email ?? owner.email, with business.name as display name. From uses config(mail.from.address) and payroll_settings.Company_name. Keep the existing Tier3 Social Security contributions for + month subject, including the Tier3 spelling.
Keep DomPDF Pdf::loadView(PDF.tier3, $data) and attachData with exact filename Tier3_social_security_controbutions.pdf. Preserve the existing controbutions spelling. Do not replace the case-sensitive PDF.tier3 view with the root tier3 view.
Country helpers directly index their supported mappings and do not define a successful fallback for unknown countries. Missing-country exceptions and unmapped-key behavior are outside this HTML-only work. Do not invent an “unsupported country but report attached” email state. PDFs/workbooks are existing generated attachments, not URLs or fixture downloads. No attachment is generated or sent in this workspace.
States and optional content
Standard report; telephone absent with address retained and a distinct application-name sample; long employer/contact values. Country variants illustrate existing attachment selection with fictional contact/label data, not additional notification types or legal validation. Empty-contact fixtures demonstrate proposed omission of blank source labels; the original views print Address/Tel labels unconditionally. This is the only conditional body cleanup introduced.
The ready HTML includes both optional rows with marked comments. In Blade, wrap each complete row in a predicate for its corresponding nonempty value. Remove the entire table when neither value exists, and remove matching lines in plain text. Preserve employer, reporting month, attachment instruction and sign-off in every state. Retain required values or fail rendering explicitly; do not invent an employer, month or scheme.
No action URL exists in this workflow. There is no button, download link, duplicate legacy action field, portal shortcut or filing action. The attachment instruction is explicit in HTML and text. Tier 2/3 previously supplied the attachment without a body instruction; this draft adds accurate PDF wording based on the Mailable. It does not say the report was filed, paid, approved or accepted.
Integration and escaping
Portable {{placeholder_name}} tokens are not automatically equivalent to Laravel Blade. Prefer a complete HTML Blade view plus a separate text view on the existing Mailable, using its native values; avoid nesting this complete document in mail::message or introducing a new framework. Keep PDF/XLSX generation, headers, recipient routing and queue behavior intact. Follow docs/integration/laravel.md.
Escape all dynamic text/attributes, including employer, scheme, app name and multiline contacts. Validate any overridden image URL separately for approved HTTPS host/path or a real attached CID. If using string replacement, use one pass and do not interpret inserted text as raw HTML or as another token. Optional rows are controlled by the integration adapter, not by blank token substitution alone.
The ready HTML includes https://built-storage.ams3.cdn.digitaloceanspaces.com/Built/app_name.png with Built alt text and proportional white-backed presentation. Retain assets/brand/built-logo.png. Use accessible absolute approved HTTPS hosting or an actual matching CID attachment in email; relative local preview assets are not deployment values. Image blocking and dark-mode cosmetics may vary by client.
Alternatives, scope and open decisions
public/ready/tier-three-report.html and .txt are portable extracts; public/previews/tier-three-report-*.html/.txt are fictional populated variants. No separate project-owned plain-text alternative was found for these Markdown views; the supplied .txt is a proposed equivalent.
Legacy direct-job bodies mails.ssnit, mails.tier2 and mails.taxreport are separate audit surfaces whose dispatch reachability remains unresolved. They have different sender/attachment contracts; these four drafts do not claim to migrate them. Do not replace a legacy job’s view merely because its title resembles a Mailable.
Integration decisions: confirm target-project field mapping, optional-contact omission, image hosting/CID, text-view registration and client approval. Review legacy filename/helper quirks separately if a behavior change is desired. No production source, statutory calculation, PDF/workbook, sender, recipient or send code is modified. Browser previews do not prove Gmail, Outlook, iOS Mail compatibility, attachment correctness or actual delivery.