Skip to main content

Split Billing — five native mechanisms

Billerang has five orthogonal native split levers built into the invoicing engine. None of them requires a validation script (validation scripts can only reject invoices, not redirect RTs). They are applied in this order:

#MechanismWhere it livesWhen it splits
1. Per-IL splitbillSeparately flag on Subscription / ServiceInstance / ChargeTemplate / ChargeInstancePer entityAuto-detected per BR scope; flagged units land in their own IL set inside the same invoice.
2. Per-IL invoice typeAccountingArticle.invoiceType + AccountingArticle.invoiceTypeElPer articleEach IL routes to the article's InvoiceType. EL evaluated against the IL.
3. Per-BC EL invoice typeBillingCycle.invoiceTypeElPer cycleEL evaluated with billingRun + billingAccount + invoice as parameters → resolves an InvoiceType code per BR/BA combination.
4. Per-BC static invoice typeBillingCycle.invoiceTypePer cycleStatic fallback when EL is empty or returns null.
5. Per-BC split by payment methodBillingCycle.splitPerPaymentMethodPer cycleOne invoice per payment method on the BA (e.g. one DIRECT_DEBIT invoice + one CHECK invoice for the same BA).

Per-run default invoice type​

A sixth knob lives directly on the BR: defaultInvoiceTypeCode (maps to BillingRun.invoiceType).

This is a per-run default, not a hard override. The article-level routing in mechanism #2 is evaluated before the BR-level fallback — articles can still produce multiple invoice types within the same run.

To force a single invoice type for the whole run, you would need to clear article-level routing (out of scope of the bill-run API).

Precedence chain in determineInvoiceType​

For each IL, the engine picks an InvoiceType in this order:

  1. BillingRun.invoiceType (the defaultInvoiceTypeCode from the request)
  2. Default prepaid / deposit / draft (special cases)
  3. BillingCycle.invoiceTypeEl (per-BC EL)
  4. BillingCycle.invoiceType (per-BC static)
  5. Default commercial invoice type

At the IL level (during aggregation), if AccountingArticle.invoiceTypeEl is set on the article assigned to the IL, that EL wins — short-circuiting the chain.

Worked examples​

Example 1 — split by payment method​

A BA has two payment methods: DIRECT_DEBIT (for the recurring fee) and CHECK (for usage charges). With BillingCycle.splitPerPaymentMethod=true, a single bill run produces two invoices:

Invoice INV_001234  (DIRECT_DEBIT, recurring fee)   €99.99
Invoice INV_001235 (CHECK, usage charges) €34.50

Both invoices reference the same BA and bill run.

Example 2 — split by article invoice type​

A merchant has two article codes:

Article "REIMB_3C"   invoiceTypeEl = "#{il.amount < 0 ? 'REIMBURSEMENT_NOTE' : 'INVOICE'}"
Article "COMMISSION" invoiceTypeEl = "INVOICE"

When the bill run produces ILs for both articles, the engine creates two invoices per BA: one of type REIMBURSEMENT_NOTE (containing the negative-amount REIMB_3C lines) and one of type INVOICE (containing the positive-amount lines).

Example 3 — split by billSeparately​

A subscription has three service instances, one of which is marked billSeparately=true. The engine adds serviceInstance.id to the GROUP BY only for that service instance — producing one extra IL set in the invoice for it. All three service instances still land in the same invoice document.

Example 4 — combining split mechanisms​

The mechanisms compose:

2 payment methods (DIRECT_DEBIT, CHECK)
× 2 article-resolved invoice types (REIMBURSEMENT_NOTE, INVOICE)
× 1 active billSeparately at SERVICE_INSTANCE level (3 instances)
= up to 12 invoices per BA, with separate IL sets within each

In practice the number is much smaller because not every combination has billable RTs.

What about validation scripts?​

Validation scripts run after invoices are created. They can:

  • Pass an invoice (status = VALIDATED)
  • Reject an invoice (status = REJECTED)
  • Flag an invoice as suspect (status = SUSPECT)

They cannot redirect RTs into different invoices — that decision is made earlier, during IL grouping and invoice creation. Use the five native mechanisms above for splitting, not validation scripts.