diff options
| author | Simen A. W. Olsen <hello@simenandre.no> | 2026-10-27 17:19:57 +0100 |
|---|---|---|
| committer | Simen A. W. Olsen <hello@simenandre.no> | 2026-10-27 17:19:57 +0100 |
| commit | 0571b30b6da27dc4c9e617403deab09b974ac641 (patch) | |
| tree | f3dfab18e22a48d06c64e563ba9bcf478c01a5bc /README.md | |
| download | accounted-multicase-intgr-0571b30b6da27dc4c9e617403deab09b974ac641.tar.gz accounted-multicase-intgr-0571b30b6da27dc4c9e617403deab09b974ac641.zip | |
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..1311a9d --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# accounted-multicase-intgr + +Example integration that sends vouchers (bilag) from a [Multicase](https://www.multicase.no) +"buntfil" export to [Accounted](https://accounted.se) through its v1 REST API. + +It reads the `.xls` export, groups the posting lines into vouchers, maps them to +Accounted journal entries and creates them as drafts, optionally posting them. + +## Install + +```sh +go install simenandre.no/accounted-multicase-intgr@latest +``` + +## Usage + +```sh +cp config.example.json config.json # then adjust the mapping + +# Parse and map every voucher, no network access +accounted-multicase-intgr check "MC Buntfil 01102026-12102026.xls" +accounted-multicase-intgr check -v "MC Buntfil 01102026-12102026.xls" # print each entry + +export ACCOUNTED_API_KEY=gnubok_sk_... # scope bookkeeping:write +export ACCOUNTED_COMPANY_ID=<company uuid> +# export ACCOUNTED_URL=https://app.accounted.se + +accounted-multicase-intgr push -dry-run export.xls # server validates, nothing is saved +accounted-multicase-intgr push export.xls # create drafts +accounted-multicase-intgr push -commit export.xls # create and post, assigning voucher numbers +``` + +`push` validates everything before it writes anything: if any voucher has an +unmapped account or VAT code, or a date outside an open fiscal period, nothing +is sent. + +## How vouchers are mapped + +- **Grouping.** Lines are grouped by `BilagsArt` and `Bilagsnummer`. Inventory + corrections (Lagerkorrigering) carry Bilagsnummer 0 and are grouped per + batch (`BuntHodeID`) instead. +- **Amounts.** `Belop` is used, in the Multicase company's base currency. + Positive is debit, negative is credit. Amounts are rounded to two decimals; + Multicase writes currency conversions with three, so a voucher can end up a + few öre off. That difference, up to `max_rounding_ore`, is posted to + `rounding_account`. Zero-amount lines are dropped. +- **Accounts.** A line whose `Konto` equals the customer number (`Faktura + kundenr`) or supplier number (`LevNr.`) is a subledger line and is posted to + `customer_ledger_account` / `supplier_ledger_account`. Every other account + must be listed in `accounts`. +- **VAT.** Multicase posts revenue and cost lines gross with an MVA code and + leaves the split to the receiving ledger. For codes with a `rate`, the net + amount stays on the mapped account and the VAT goes to the code's `account`. + Codes with rate 0 pass through untouched. +- **Dimensions.** `AvdNr.` and `Prosjekt` are sent as the SIE dimensions named + in `dimensions` (by default 1, kostnadsställe, and 6, projekt). + +`config.example.json` maps the accounts found in one Print Supplies AS export +to BAS 2026 accounts. It is a starting point only: have the mapping, and in +particular the VAT codes, checked by whoever keeps the books. + +## Not booking twice + +Each voucher is sent with `source_id` `multicase:<BilagsArt>:<Bilagsnummer>` +and a deterministic `Idempotency-Key`, so retries after a timeout are replayed +by the server rather than repeated. Accounted keeps idempotency keys for 24 +hours, so `push` also records every draft and posted voucher in +`multicase-state.json`. Re-running an overlapping export skips what was sent. + +A voucher that changed in Multicase after it was sent is reported and skipped. +Posted vouchers cannot be edited; correct them in Accounted (storno or rättelse). + +## Limitations + +- Accounted keeps its ledger in SEK. Amounts are sent as they appear in + Multicase, so the export's base currency must match the Accounted company's. +- Only the first worksheet of the export is read, and only Excel 97-2003 + (`.xls`) files are supported. The bundled BIFF8 reader exists because the + available Go libraries decode negative whole-number cells as large positive + numbers. +- Requests are throttled to stay under the default limit of 100 requests per + minute per API key; 429 and 5xx responses are retried. |
