feat: email receipts and repair estimates
Backend: - Server-side HTML email templates (receipt + estimate) with inline CSS - POST /v1/transactions/:id/email-receipt with per-transaction rate limiting - POST /v1/repair-tickets/:id/email-estimate with per-ticket rate limiting - customerEmail field added to receipt and ticket detail responses - Test email provider for API tests (logs instead of sending) Frontend: - POS payment dialog Email button enabled with inline email input - Pre-fills customer email from linked account - Repair ticket detail page has Email Estimate button with dialog - Pre-fills from account email Tests: - 12 unit tests for email template renderers - 8 API tests for email receipt/estimate endpoints and validation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -87,6 +87,21 @@ class SmtpProvider implements EmailProvider {
|
||||
}
|
||||
}
|
||||
|
||||
class TestProvider implements EmailProvider {
|
||||
static lastEmail: SendOpts | null = null
|
||||
static emails: SendOpts[] = []
|
||||
|
||||
async send(opts: SendOpts): Promise<void> {
|
||||
TestProvider.lastEmail = opts
|
||||
TestProvider.emails.push(opts)
|
||||
}
|
||||
|
||||
static reset() {
|
||||
TestProvider.lastEmail = null
|
||||
TestProvider.emails = []
|
||||
}
|
||||
}
|
||||
|
||||
export const EmailService = {
|
||||
async send(db: PostgresJsDatabase<any>, opts: SendOpts): Promise<void> {
|
||||
const provider = await SettingsService.get(db, 'email.provider')
|
||||
@@ -99,8 +114,14 @@ export const EmailService = {
|
||||
return new SendGridProvider(db).send(opts)
|
||||
case 'smtp':
|
||||
return new SmtpProvider().send(opts)
|
||||
case 'test':
|
||||
return new TestProvider().send(opts)
|
||||
default:
|
||||
throw new Error('Email provider not configured. Set email.provider in app_settings.')
|
||||
}
|
||||
},
|
||||
|
||||
getTestEmails: () => TestProvider.emails,
|
||||
getLastTestEmail: () => TestProvider.lastEmail,
|
||||
resetTestEmails: () => TestProvider.reset(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user