1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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.
|