Developer notes
Technical reference for developers who customize Xero Accounting Sync.
Add-on identity
Section titled “Add-on identity”| Item | Value |
|---|---|
| Add-on id | kv_xero |
| Function prefix | fn_kv_xero_ |
| Language variables | kv_xero.* |
| CSS scope | .kv-xero |
| PHP namespace | Tygh\Addons\KvXero |
| Preset | accounting (generated by kv new --kind integration) |
Structure
Section titled “Structure”| Class | Role |
|---|---|
Client\BaseClient |
HTTP (cURL, TLS verification, timeouts), JSON, Retry-After and rate limit headers, error mapping, masked logging |
Client\Api |
OAuth 2.0 (authorization code, rotating refresh token under a database lock) and the Accounting API calls |
Client |
Client per company, the connection test |
Sync |
Contact, invoice, payment, credit note, refund and item sync; tax allocation; the map table |
Accounts, Secret |
Credentials (test and live) sealed with AES-256-GCM; one account per store owner or per vendor |
Config, Access |
Settings, owner mode, who may see and manage what |
Queue, Jobs, JobException |
Job queue: back-off 5 min / 15 min / 1 h / 3 h / 12 h, per-job isolation, overlap lock; handlers in Jobs::handle(), recurring work in Jobs::schedule() |
Log |
Event log with masking, filters, CSV, retention |
Database tables
Section titled “Database tables”| Table | Purpose |
|---|---|
?:kv_xero_accounts |
Credentials per company (secrets sealed), last connection check, token cache |
?:kv_xero_log |
Log |
?:kv_xero_jobs |
Queue |
?:kv_xero_map |
What was sent to the accounting system (Xero ids, payload hash) |
Hooks used
Section titled “Hooks used”PHP hook change_order_status_post (queues the invoice, payment and credit note jobs). Template hooks: only the License card in the add-on settings. Nothing is printed on the storefront, so full page cache and Varnish are unaffected.
Test the HTTP layer without Xero
Section titled “Test the HTTP layer without Xero”The base URL can be overridden for tests in config.local.php (development only):
$config['kv_xero_base_url'] = 'http://127.0.0.1:11923';node tests/mock-server/server.js 11923 starts a local stand-in of the Xero identity service and Accounting API; node tests/e2e/e2e.mjs runs the end-to-end test (real orders, OAuth flow, refunds) against it; php tests/unit.php runs the unit tests.
Template overrides
Section titled “Template overrides”Admin templates live in design/backend/templates/addons/kv_xero/. Do not edit them in a store; they are replaced on update.
- API sources: Xero’s published OpenAPI descriptions (github.com/XeroAPI/Xero-OpenAPI:
xero_accounting.yaml,xero-identity.yaml). The rate limits (60 calls a minute, 5,000 a day per organisation,Retry-Afteron 429) and the 60 day rolling refresh token come from Xero’s developer documentation, whose pages could not be fetched as text during development: check them against developer.xero.com. - Refresh tokens are single use.
Accounts::locked()serialises the refresh withGET_LOCK, and a second process re-reads the account after the lock, so cron and an admin click never burn the same token. - Idempotency keys:
kv-inv-<order>-<hash>,kv-pay-<order>,kv-cn-<order>,kv-rf-<order>,kv-al-<order>. - Map table entities: customer, invoice, payment, credit, refund (payment or allocation), item.
- CS-Cart stores taxes either per line (
appliesP_) or per order (subtotal calculation); Sync::allocate()handles both.