AquaDealers uses a dual WhatsApp implementation: client-side wa.me links for manual sends, and a server-side Edge Function via the authkey.io API for automated bill delivery.
Builds https://wa.me/91{phone}?text={encoded} URLs and opens them in a new browser tab. The user must then press "Send" in WhatsApp Web or the WhatsApp app. No server round-trip required.
All phone numbers are cleaned before use:
+91 prefix if present0s| Function | Purpose | Usage |
|---|---|---|
openWhatsAppText() | Send a text message | Reports, statements, reminders |
sharePdfViaWhatsApp() | Share a PDF file | Downloads the PDF via a hidden <a download> link, then opens a blank wa.me chat for the user to manually attach the file |
requirePhone() | Guard function | Prompts user to add farmer phone number if missing before attempting send |
All templates are defined in whatsAppMessages.ts. Each template builds a formatted text string with dynamic data:
| # | Template | Variables | Used In |
|---|---|---|---|
| 1 | Invoice | Bill items, total, balance, date | Bill details page, checkout success |
| 2 | Balance Reminder | Farmer name, outstanding amount | Farmer ledger, dues page |
| 3 | Statement | Farmer name, period dates, closing balance, shop name | Farmer statement page |
| 4 | Delivery PIN | 4-digit confirmation PIN | Delivery confirmation flow |
| 5 | Collection Reminder | Farmer name, amount due, shop name | Dues page |
| 6 | Daily Summary | Today's sales, cash received, credit given, shop name, date | Daily book / end-of-day |
| 7 | Dues Report | Farmer count with dues, total outstanding, shop name | Dues report page |
| 8 | Stock Report | Period dates, shop name | Stock report page |
| 9 | Farmer Items | Products a farmer has purchased | Farmer detail page |
| 10 | Expiry Report | Expiring item count, shop name | Dashboard expiry widget |
send-bill-whatsapprequestjson.php| Variable | Purpose |
|---|---|
AUTHKEY_TOKEN | API authentication token for authkey.io |
AUTHKEY_BILL_WID | WhatsApp template ID for bill messages |
useCheckout.ts (online) or synced via offlineBillStore.ts (offline bills).catch(() => {}) — failure never blocks checkoutrequestjson.phpAccess-Control-Allow-Origin: *. This is a known security issue (see Security page).null → 'sending' → 'sent' | 'failed'
The whatsapp_status column on the bills table tracks delivery status:
| Status | Meaning | UI Treatment |
|---|---|---|
null | Not yet attempted | No indicator |
sending | Request in flight | Spinner / "Sending..." |
sent | Accepted by authkey.io | Green checkmark |
failed | Request failed or quota exceeded | "Retry" button shown |
sending after 6 polls, UI stops polling (does not mark as failed)The failure_reason column stores a human-readable reason for debugging. Failed sends show a "Retry" button in:
| Table | Purpose | Key Columns |
|---|---|---|
whatsapp_addon_plans | Plan definitions | plan name, messages_per_month, price |
whatsapp_message_usage | Monthly usage tracking | dealer_id, month_year, messages_sent |
check_and_increment_whatsapp_usage RPC is calledmessages_sent against plan's messages_per_month and increments the counter if within quota'failed', reason set to 'quota_exceeded'| Scenario | Behavior |
|---|---|
| Edge function HTTP error | Checkout succeeds; bill status = failed; "Retry" button shown |
| authkey.io rejects request | Same as above |
| Quota exceeded | Status = failed, reason = quota_exceeded |
| Network timeout | Checkout succeeds; status may stay sending indefinitely |
| authkey.io HTTP 200 but no delivery | No way to detect. authkey.io does not provide delivery webhooks |
sent status means "sent to authkey.io", not "delivered to WhatsApp".