# School fee reminders

Remind parents of balances with an approved template and track delivery.

> **In a nutshell:** Pick the APPROVED fees template, fill its placeholders per student, send each with your own reference from a queue, and update the reminder's status from message.status callbacks.

## The flow

1. **Load the template.** `GET /businesses/{school}/whatsapp/templates?status=APPROVED&amp;name=fees_reminder` - cache it.
2. **Create your rows first.** One reminder row per parent in your database, status `pending`.
3. **Send from a queue.** For each row, `POST .../messages` with `type: template` and `reference: "fee-reminder-{row id}"`. Store `data.id`.
4. **Track.** `message.status` callbacks carry your reference - move the row to sent, delivered, read or failed.

## The template

Created by the school in WhatsApp Manager (category `UTILITY`):

```text
Dear {{1}}, the fees balance for {{2}} is GHS {{3}}. Please pay before {{4}}.
```

## Sending

```php
foreach ($reminders as $reminder) {
    SendFeeReminder::dispatch($reminder->id); // queued; see Safe retries
}

// In the job:
Http::withToken(config('services.paalchat.token'))->acceptJson()
    ->post("https://whatsapp.paaltech.org/api/v1/businesses/{$tenantId}/messages", [
        'to' => $reminder->parent_phone,
        'type' => 'template',
        'reference' => 'fee-reminder-'.$reminder->id,
        'template' => [
            'name' => 'fees_reminder',
            'language' => 'en_US',
            'components' => [['type' => 'body', 'parameters' => [
                ['type' => 'text', 'text' => $reminder->parent_name],
                ['type' => 'text', 'text' => $reminder->student_name],
                ['type' => 'text', 'text' => number_format($reminder->balance, 2)],
                ['type' => 'text', 'text' => $reminder->due_date->format('j F')],
            ]]],
        ],
    ])->throw();
```

```javascript
for (const r of reminders) {
  await queue.add('fee-reminder', { id: r.id });
}
// worker
await fetch(`${BASE}/businesses/${school}/messages`, { method: 'POST', headers: HEADERS, body: JSON.stringify({
  to: r.parentPhone, type: 'template', reference: `fee-reminder-${r.id}`,
  template: { name: 'fees_reminder', language: 'en_US', components: [{ type: 'body', parameters: [
    { type: 'text', text: r.parentName }, { type: 'text', text: r.studentName },
    { type: 'text', text: r.balance.toFixed(2) }, { type: 'text', text: r.dueDate }] }] },
}) });
```

## Tracking

```json
"data": {"reference": "fee-reminder-4411", "status": "failed", "error": {"code": "131026", "message": "Recipient is not on WhatsApp"}}
```

Show failed reminders to the bursar so they can call or SMS those parents instead.

> [!TIP]
> Send reminders during the day. Messages at night get blocked more often, which
> lowers the number's quality rating.
