# 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= # 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::` 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.