Account roles
A role says which account a service posts to: invoices debit the account with the role
ar_control, the FX revaluation books to fx_unrealized, the year's result goes against
retained_earnings. One account of an entity holds a role and an account holds at most one (a
unique index). The chart of accounts is the customer's own, imported or edited, so an existing
account has to be able to take a role afterwards: PATCH /v1/entities/{entity}/accounts/{code}
(ADR-0029, X4). The reference is
Setup; this page is the rules.
The catalogue is src/erp/modules/role_catalogue.py: one list of every role, the account types
it may have, whether it is a control role and, for the optional ones, the statement line the chart
templates suggest.
Required and optional roles
| Kind | Roles | What it means |
|---|---|---|
| Required | bank, ar_control, ap_control, vat_input, vat_output, vat_reverse_charge, retained_earnings, fx_gain, fx_loss, fx_unrealized, rounding, suspense, fixed_asset_cost, accumulated_depreciation, depreciation_expense, asset_disposal_gain, asset_disposal_loss, default_revenue, default_expense, bank_fees, cash_discount_granted, cash_discount_received, opening_balance_clearing, payments_in_transit (outgoing payments awaiting execution by the bank, ADR-0060) |
every entity has them; the chart templates carry one account each, and POST /v1/entities/{entity}/role-accounts adds the ones an older entity lacks |
| Optional | annual_result (the year's result until the shareholders resolve on it, year-end close), vat_settlement, vat_oss (the VAT of sales declared on the EU One-Stop Shop return, ADR-0068), vat_carry_forward and vat_refund_receivable (a negative VAT result carried to the next return, and one whose refund is due: the Spanish 470000 and 470900, ADR-0065), vat_interest (the 1 % interest an Italian quarterly filer pays on its VAT, the Italian 7520 and the IFRS 7120, ADR-0066), vat_net_rate_difference, goods_revenue (the sales of goods apart from services: a product sold as goods books here unless it names its account; every chart but SKR04 and NS 4102, whose one revenue account takes all sales, products), provider_balance (what a payment provider such as Shopify Payments holds for the company until its payout: a receipt that names the account books there as at a bank, though it is never a bank account a payment defaults to; every chart, KMU 1092, Shopify), goods_purchases (the purchases of goods for resale in a chart that books them apart from the change in stock: SKR04 6100, PCG 607000, PGC 600000, Italy 6000, BAS 4010, NS 4102 4300, Finland 4000, Denmark 2000; goods bought for a customer and never in stock book here, else to cogs, Shopify), qst_output, qst_input and qst_settlement (the Quebec QST collected, refundable and settled, beside the GST/HST on the VAT accounts) and pst_payable_bc, pst_payable_sk and rst_payable_mb (the provincial sales tax collected for each province; ADR-0063), pst_settlement (what the provincial returns settle to) and gst_instalments (GST/HST instalments paid, credited on the year's return; ADR-0067), vat_input_investments (input VAT on investments and other operating costs beside vat_input, the Swiss 1171, ADR-0058), deferred_tax_asset, deferred_tax_liability, deferred_tax_expense, ic_ar_control and ic_ap_control (the receivables from and payables to group companies for trade documents), ic_other_receivable, ic_other_payable, ic_loan_receivable, ic_loan_payable, ic_interest_income, ic_interest_expense and ic_dividend_income (loans, interest and dividends between group companies, intercompany), withholding_tax_payable and withholding_tax_receivable (the Swiss withholding tax a dividend deducts and the claim of its recipient, year-end close), vendor_withholding_payable (the tax kept back from vendor bills and owed to the tax authority, withholding tax), dunning_income (the default interest and dunning fees a reminder letter charges, dunning), contract_liability, contract_asset and unbilled_receivable (what a revenue contract has billed ahead of its revenue, and the revenue recognised ahead of billing, revenue contracts), bad_debt_expense, allowance_expense and receivable_allowance (written-off receivables, the change of the allowance and the allowance for doubtful receivables, bad debts), inventory, cogs, inventory_adjustment and grni (the stock, its cost of goods sold, count differences and goods received not invoiced, stock), lease_right_of_use, lease_accumulated_depreciation, lease_liability, lease_interest and lease_cost (a lessee's right-of-use assets, their depreciation, the lease liabilities, their interest and an ASC 842 operating lease's single lease cost; the IFRS and US charts have the first four, the US chart also 6110 Operating lease cost, a local chart adds them when it reports under IFRS 16, leases), operating_lease_right_of_use, operating_lease_accumulated_amortization and operating_lease_liability (an ASC 842 operating lease's asset and liability, apart from a finance lease's: the US chart's 1730, 1739 and 2760; their cash flows are operating activities), asset_sale_clearing (the net proceeds of an asset sold on a sales invoice, between the invoice and the asset's own entry), asset_impairment_loss (impairments of fixed assets, and their reversal by a revaluation) and revaluation_surplus (the equity reserve of revalued assets, on the IFRS, FRS 102 and Canadian charts only; fixed assets) |
an entity works without them until it uses the capability; a capability adds its own roles to the catalogue (the year-end close adds annual_result, intercompany its accounts) |
| Control | bank, payments_in_transit, ar_control, ap_control, fixed_asset_cost, accumulated_depreciation, annual_result, ic_ar_control, ic_ap_control, ic_other_receivable, ic_other_payable, ic_loan_receivable, ic_loan_payable, contract_liability, contract_asset, unbilled_receivable, inventory, grni, lease_right_of_use, lease_accumulated_depreciation, operating_lease_right_of_use, operating_lease_accumulated_amortization, asset_sale_clearing, receivable_allowance (and the control roles of later capabilities) |
the account takes postings only from its subledger or process (posting.SUBLEDGER_SOURCES) |
What a change checks
A request is {"name": "...", "role": "...", "report_line": "...", "active": true|false, "reason": "..."}; only the fields sent change, and "role": null takes a role away. The account's number,
type and currency are fixed.
- The role is known and fits. An unknown role, or one for another account type (a
bankrole on an expense account), is422; the legacyasset_disposalrole is never assigned again. - The role is free. Another account that holds it is named (
409): take it away from that account first. - A control role is refused on an account with a manual history (
409, naming the entries): a control account takes postings only from its subledger, so an account that already has drafts, approvals or postings from outside the subledger sources (posting.SUBLEDGER_SOURCES) cannot become one (control L7). Assigning a control role also marks the account as a control account, and taking the control role away makes it an ordinary account again (is_controlis cleared). - A second person decides a change to or from a control or required role, and of the
statement line of an account that holds one. The approval policy's
action
change_required_account_role(human-only, defaultrequire_approval) turns the request into an approval: the answer is202withstatus: pending_approvaland theapproval_id, the account stays as it is, and another person approves it withPOST /v1/approvals/{approval_id}/approve(the approver is never the requester, whichever key or session). The approval is checked again against the account as it is then; if it no longer holds (a manual posting arrived on the account meanwhile) the approval is refused with409and the request can be rejected. One request per account at a time. The role of an ordinary account (an optional, non-control role) changes at once; a one-person organization allowschange_required_account_rolein its own policy (PUT /v1/approval-policy). - A new name applies at once, also on an account with a control or required role and in a
closed period: a name moves no amount and nothing keys an account by it (reports, exports and the
services use its id or code), and the audit keeps the previous name (GoBD: traceable, not
prevented). It is one line without control characters (
422). On an asset account it may not drop or change an IBAN in the name, nor add one another account's name carries (409): a bank statement import without a registered IBAN finds its account by the IBAN in the name. - An account that holds a role cannot be deactivated (
409): the services could not post to it. Nor can a control account; an account the books still carry a balance on (a balance-sheet account's balance, or a profit and loss account's result in a fiscal year not closed to zero); one that unfinished work names (an entry, invoice or bill not yet posted, an open purchase order, a draft payment, a recurring invoice that has not ended); or one that something posts to later (a fixed asset, product, subscription, revenue contract, party default, bank account, depreciation book, intercompany loan, the VAT settings): the answer names why. A report line must be one that holds the account's type: each line of the vocabulary inseed/consolidation_frameworks.yamlholds one type (pl.opex.otherholds expense accounts).
Audit
| Event | When | Data |
|---|---|---|
account.role.change |
a role is given, changed or taken away | previous and new role, reason, and for an approved change requested_by and approval_id |
account.role.request |
a change waits for a second person | the previous role, the proposed one, approval_id, reason |
account.role.reject |
the second person rejects it | approval_id, comment |
account.update |
the name, the report line or active changes |
previous and new values |
Example
# the customer's chart has its own retained-earnings account: it takes the role (a second person approves)
curl "${H[@]}" -X PATCH "$ERP_URL/v1/entities/CH01/accounts/2971" -d '{"role": "retained_earnings"}'
# 409: 2970 holds it; give it up first (also a request, as it is a required role)
curl "${H[@]}" -X PATCH "$ERP_URL/v1/entities/CH01/accounts/2970" -d '{"role": null, "reason": "Our chart uses 2971"}'
# 202 {"status": "pending_approval", "approval_id": "...", "changed": ["role"], "account": {...}}