# Sale WhatsApp notifications

The `App\Services\WhatsAppSms` service sends text messages through Flaxxa. No SMS provider is used.

## Setup

1. Install dependencies with `composer install`.
2. Start the application's MySQL server, then run the new migration:

   ```powershell
   php artisan migrate --path=database/migrations/2026_10_01_000001_create_whatsapp_tables.php
   ```

3. Open **Admin Settings → WhatsApp** (`/admin/settings?tab=whatsapp`). Enable WhatsApp, enter the Flaxxa token and sender number, and enable **New sale completed**. Pakistan is fixed for local numbers: `03001234567` and `923001234567` normalize to `+923001234567` automatically. No country selection is required, including for previously saved settings.
4. Choose whether to show the Send / Skip popup. With popup off, enabled sale notifications are automatically queued.
5. The current application uses `QUEUE_CONNECTION=database`. Keep a queue worker running:

   ```powershell
   php artisan queue:work --queue=default --tries=1 --timeout=45
   ```

   Use a process supervisor in deployment. The existing `composer run dev` also starts the application's queue listener. Without a worker, messages remain **Pending**, not sent. Worker setup was not activated against the local database because MySQL was stopped during implementation.

Restart existing queue workers after deploying code. Keep Laravel's `APP_KEY` stable: it encrypts the token and notification snapshots.

## Direct settings test

In **Admin Settings → WhatsApp → Send a test WhatsApp message**, enter your test number and message, then click **Send Test WhatsApp**. Save the token and sender first; unsaved settings are not used. The test sends immediately without a queue worker and works with automatic notifications disabled. Settings edit permission is required. A business can send one test per 45 seconds to prevent accidental repeated requests. Tests do not create sales or sale-history entries.

The result shows a sanitized outcome and HTTP status when available. HTTP 200/201 alone cannot verify token validity or delivery: check the destination WhatsApp for receipt. Provider error bodies and tokens are never displayed.

## Behavior

- Only a new normal POS sale triggers a message, including fully paid, partial and credit sales. Editing an invoice, quotations, exchanges and customer receipts do not trigger it.
- The recipient comes exclusively from the saved customer's phone. Missing/invalid numbers and walk-in sales are skipped without blocking checkout.
- Stock, account balances, FBR submission and the print event run independently before WhatsApp preparation. Send / Skip does not resubmit the sale.
- One notification per business, invoice and event is enforced by a database unique key. Atomic transitions prevent repeated clicks and repeated job execution from sending twice.
- Settings are business-wide; notification history is limited to the current business and branch. Jobs explicitly use business/branch IDs instead of session scopes.
- Notification history shows the latest 15 attempts in the Settings tab. Use Refresh to update it. A closed/reloaded confirmation stays awaiting confirmation and is never automatically sent.
- Disabling WhatsApp or sale notifications also stops pending jobs when the worker processes them. A request already in progress cannot be recalled.
- Templates use the invoice's saved total and paid amount. Invoice remaining means this invoice's balance, not the customer's total ledger balance. The default currency text is PKR, matching the existing POS; the text can be edited. Dates use `config('app.timezone')`.

## Provider contract and limits

POST `https://wapi.flaxxa.com/api/v1/sendmessage` with exactly four URL-encoded fields: `token`, `phone`, `to`, `message`. Token is in the body, not a Bearer header. SSL verification stays enabled. Both connection and request timeouts are 30 seconds.

The request contract comes from the supplied reference integration. An official response/delivery schema could not be verified. Explicit error flags and HTTP 4xx responses are failures; otherwise the status is **Unknown**, with the HTTP status recorded. HTTP 200/201 does not claim acceptance or delivery. Connection failures/timeouts are also unknown because the provider may already have sent the message. There are no automatic retries and no inferred delivery IDs, media support or delivery callbacks. A sanitized successful provider response and documented schema are needed to add reliable Accepted/Delivered mapping.

Tokens never return to the settings form after saving; leaving the field empty preserves the token. Tokens and recipient/message snapshots are encrypted at rest. Provider response bodies and exception messages are not logged or displayed. Jobs contain only IDs.

## Validation

```powershell
php artisan test --filter=WhatsApp
php artisan test
```

Tests use isolated SQLite and mocked HTTP; no live customer messages are sent. Checkout tests adapt existing MySQL-only migration/backfill steps for SQLite without changing those production migrations. They exercise real Livewire settings and checkout, including printing events, partial/credit/paid sales, Send/Skip, automatic sending, failures, ownership and duplicate protection. Browser print-dialog behavior and real Flaxxa delivery still require a configured running application.
