voxtelesys_integration/README.md

183 lines
7.2 KiB
Markdown

# Voxtelesys Integration for ERPNext / Frappe Helpdesk
Frappe app that wires the **Voxtelesys** voice + SMS platform into ERPNext —
giving Helpdesk agents click-to-call, inbound call popups, agent routing,
call recording, SMS send/receive, and auto-ticketing on missed calls.
Two architectures are supported and can run side by side:
| Path | Use when | Endpoint |
| --- | --- | --- |
| **Direct API** (v2.x) — ERPNext talks to Voxtelesys directly | You want click-to-call, agent routing, SMS, and recording driven from the desk UI | `api.voxtelesys.handle_inbound_call`, `api.sms.handle_inbound_sms` |
| **3CX bridge** (v1.x, legacy) — 3CX brokers calls, ERPNext just auto-creates tickets | Your 3CX PBX already routes inbound calls and you only want ticketing on the ERPNext side | `api.inbound_call` |
---
## Architecture overview
### Direct API path
```
Caller ── PSTN ──→ Voxtelesys ──webhook──→ ERPNext
├─ writes Voxtelesys Call Log
├─ creates HD Ticket on missed call
├─ rings agent (Round Robin / Availability)
└─ returns VoXML <Dial> → call connects to agent's phone
```
### 3CX bridge path
```
Caller ── PSTN ──→ Voxtelesys SIP trunk ──→ 3CX PBX
├─ rings extensions normally
└─ CF_URLFetch ─→ ERPNext (creates HD Ticket only)
```
---
## Installation
```bash
cd ~/frappe-bench
bench get-app https://forge.wilddragon.net/zgaetano/voxtelesys_integration.git
bench --site erp.broadcastmgmt.cloud install-app voxtelesys_integration
bench --site erp.broadcastmgmt.cloud migrate
bench restart
```
After install, three custom fields are added via fixtures:
- `User.custom_voxtelesys_number` — E.164 number to ring for inbound routing
- `HD Ticket.custom_voxtelesys_call_sid` — dedup for direct-API missed-call tickets
- `HD Ticket.custom_3cx_call_id` — dedup for 3CX-bridge tickets
---
## Configuration (direct API path)
1. **Get a Voxtelesys API token** from the [Voxtelesys developer portal](https://developer.voxtelesys.com/apis/authorization/).
2. Open **Voxtelesys Settings** in ERPNext and fill in:
- **Voxtelesys API Token** (Bearer token)
- **Default Caller ID** (E.164, used for outbound voice and SMS)
- **Public Base URL** (e.g. `https://erp.broadcastmgmt.cloud`)
- **Webhook Signing Secret** (optional but recommended — HMAC-SHA256)
- **Enable Call Recording** if desired
- **Inbound Call Routing** (`Round Robin`, `Availability-Based`, or `Direct (no routing)`)
3. Copy the two **Webhook URLs** shown in Voxtelesys Settings and paste them into:
- Voice API Profile → Answer URL: `…/api/method/voxtelesys_integration.api.voxtelesys.handle_inbound_call`
- SMS Profile → Inbound Webhook: `…/api/method/voxtelesys_integration.api.sms.handle_inbound_sms`
4. Tick **Enabled** and save.
5. Test with the **Test API Connection** button on Voxtelesys Settings.
### Agent routing setup
For Round Robin / Availability-Based routing to work, each agent's **User**
record needs a `Voxtelesys Number` set (the field is added automatically by
the fixture). This is the actual phone number Voxtelesys will dial — usually
the agent's cell or desk phone DID, in E.164.
---
## Configuration (3CX bridge path)
1. **3CX → Management Console → Call Flow Designer**
2. Create or edit the Call Flow for your inbound DID
3. Add a **CF_URLFetch** block:
- **URL**: `https://erp.broadcastmgmt.cloud/api/method/voxtelesys_integration.api.inbound_call`
- **Method**: POST
- **Parameters**:
- `caller_id` = `[caller_id]`
- `called_did` = `[called_did]` (optional)
- `call_id` = `[call_id]` (recommended — enables dedup)
4. Optional secret token: `bench --site … set-config voxtelesys_webhook_secret yourtoken` and append `?secret=yourtoken` to the URL.
---
## Usage
### Click-to-call
- **HD Ticket form**: a "Voxtelesys → Call ..." button appears in the
toolbar whenever the ticket's linked Contact has a mobile / phone number.
- **Lead / Contact forms**: same button group; works on any Phone field via
the `frappe.phone_call.handler` override.
- A floating call bar appears at the bottom of the screen showing live call
status. Clicking "Open Log" jumps to the Call Log entry.
### Inbound calls
When a call hits the inbound webhook, the agent on shift gets a popup with
the caller's number and a "Ringing…" indicator. If no agent answers, a
**missed-call HD Ticket** is auto-created (toggle via Voxtelesys Settings →
*Auto-create Helpdesk Ticket on Missed Call*).
### SMS
- **Send**: "Voxtelesys → Send SMS" button on HD Ticket and Lead forms.
- **Receive**: inbound MO messages from a known Contact with an open HD
Ticket are automatically appended as a `Communication` row on the ticket
thread (toggle via Voxtelesys Settings → *Auto-attach Inbound SMS to Open
Ticket*).
- All messages are persisted to the **Voxtelesys SMS Log** doctype with
Dynamic Link entries for cross-referencing.
---
## DocTypes
| Name | Purpose |
| --- | --- |
| **Voxtelesys Settings** | Single — global config |
| **Voxtelesys Call Log** | One row per call (in or out) with status, duration, recording URL, links |
| **Voxtelesys SMS Log** | One row per SMS (in or out) with body, status, delivery receipt, links |
---
## Scheduled jobs
- `sync_pending_call_logs` runs every 5 minutes to reconcile any Call Log
rows stuck in `Ringing` or `In Progress` because a status webhook was
missed. Configured in `hooks.py:scheduler_events`.
---
## Whitelisted API surface
| Method | Auth | Purpose |
| --- | --- | --- |
| `voxtelesys_integration.api.voxtelesys.handle_inbound_call` | guest | Voxtelesys voice webhook |
| `voxtelesys_integration.api.voxtelesys.handle_call_status` | guest | Voxtelesys status callback |
| `voxtelesys_integration.api.voxtelesys.make_outbound_call` | user | Click-to-call from desk UI |
| `voxtelesys_integration.api.voxtelesys.test_connection` | sysmgr | Settings → Test button |
| `voxtelesys_integration.api.voxtelesys.get_linked_call_logs` | user | Form sidebar history |
| `voxtelesys_integration.api.sms.send_sms` | user | Send SMS from desk UI |
| `voxtelesys_integration.api.sms.handle_inbound_sms` | guest | Voxtelesys SMS webhook |
| `voxtelesys_integration.api.sms.get_linked_sms_logs` | user | Form sidebar SMS history |
| `voxtelesys_integration.api.inbound_call` | guest | Legacy 3CX CF_URLFetch entrypoint |
Guest endpoints verify a HMAC-SHA256 signature in the
`X-Voxtelesys-Signature` header against the **Webhook Signing Secret** in
settings (if configured). The legacy 3CX endpoint uses a query-string
`?secret=` token from `site_config.json` instead.
---
## Development
```bash
cd ~/frappe-bench/apps/voxtelesys_integration
git remote -v # should point at forge.wilddragon.net
bench --site erp.broadcastmgmt.cloud clear-cache && bench restart
```
To export updated fixtures after editing custom fields in the UI:
```bash
bench --site erp.broadcastmgmt.cloud export-fixtures --app voxtelesys_integration
```
---
## License
MIT