# Smart billing reminder automation

This module sends **customer-facing email** notifications for invoices, quotations, payments, purchase orders, recurring billing, and manual follow-ups. It is built for **Laravel 11**, **queues**, and **shared hosting** (database queue driver supported).

## What it does

- **Automatic emails** when documents change (e.g. invoice created, quotation accepted) — see `App\Services\ReminderService`.
- **Scheduled reminders** for due soon, overdue invoices, and quotation expiry — command `php artisan reminders:process` (hourly via scheduler in `routes/console.php`).
- **Admin UI**: Settings → **Billing Reminders** & **Reminder Email Templates**; Reports → **Reminder Logs**.
- **Manual send** from invoice and quotation detail pages (permission: `send_manual_reminders`).
- **Logging** in `reminder_logs` with status `pending` / `sent` / `failed`.

> **Note:** Transactional emails use one mailable pattern (`App\Mail\Reminders\DynamicReminderMail`) plus rows in `email_templates`. Older slugs from `EmailTemplateSeeder` (e.g. `invoice-created`) are separate legacy templates.

## Configuration

1. **SMTP / mail driver** — set standard Laravel `.env` keys (`MAIL_MAILER`, `MAIL_HOST`, `MAIL_PORT`, etc.). No credentials are stored in the database.
2. **Reminder toggles & timing** — Admin → Settings → System Settings → **Billing Reminders**.
3. **Queue vs instant** — Same screen: **Queue** (recommended) dispatches `SendReminderEmailJob`; **Instant** runs the job synchronously.
4. **Templates** — Admin → **Reminder Email Templates**. Placeholders use `{key}` (and `{{key}}` is supported for legacy bodies). Preview uses sample data; **Reset** re-runs `ReminderSystemSeeder` for that slug set.

## Cron & scheduler

Add a single cron entry (adjust path):

```cron
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
```

The app schedules `reminders:process` **hourly** (see `routes/console.php`). For **queued** mail, also run a worker:

```bash
php artisan queue:work --queue=default --tries=3
```

On shared hosting, use the **database** queue driver in `.env` and a cron that runs `queue:work` periodically, or use `schedule:run` with a queued job batch — see Laravel docs for your host limits.

## Permissions (re-seed after update)

- `manage_reminders` — settings page  
- `manage_email_templates` — template editor  
- `send_manual_reminders` — manual send + modals on invoice/quotation  
- `view_reminder_logs` — reports  

Run:

```bash
php artisan db:seed --class=RolePermissionSeeder
```

(Or your usual permission sync.) Super admin role bypasses permission middleware.

## Database

- `reminder_settings` — feature flags and intervals.  
- `reminder_logs` — audit trail.  
- `email_templates` — extended with `module` and `default_template` for billing templates.

Fresh installs: `DatabaseSeeder` calls `ReminderSystemSeeder` after `EmailTemplateSeeder`.

## Duplicate prevention

Automated types (not manual / follow-up) skip sending if a **successful** log already exists for the same **reminder_type** + **invoice_id** or **quotation_id** on the **same calendar day** (`ReminderService::wasSentToday`).

## Troubleshooting

| Issue | Check |
|--------|--------|
| No emails | `.env` mail settings, `php artisan config:clear`, mail log driver for debugging |
| Stuck on pending | Queue worker running; `failed_jobs` table |
| Template empty | Run `php artisan db:seed --class=ReminderSystemSeeder` |
| 403 on admin pages | Role permissions / super admin |
| PDF not attached | `attach_pdf_to_emails` in settings + supported reminder type in `ReminderService` |

## Extending (SMS / WhatsApp / push)

Implement `App\Contracts\Reminders\ReminderChannelInterface` and call from a future dispatcher alongside `SendReminderEmailJob`. Keep channel-specific credentials in `.env` or encrypted settings, not in templates.
