FinzBooksDevelopers

Round-off

Invoice (and bill) totals can drift to fractional rupees when a tax percentage produces an inexact float (e.g. 18% of ₹199.43 = ₹35.8974). The round-off feature snaps the grand total to a whole rupee and posts the difference to a dedicated Round Off ledger.

Turn it on

Via the UI

Settings → Invoice Profile → toggle Round invoice totals automatically, pick a rounding method, Save. The preference is stored in organisations.preferences.roundInvoiceTotals and is applied to every invoice creation path (UI, API, recurring runs).

Via API

PUT /api-py/api/v1/organisations/<org_id>/preferences

{
  "preferences": {
    "roundInvoiceTotals": true,
    "roundingMethod": "nearest"     // "nearest" | "up" | "down"
  }
}

Note: this is an internalendpoint (session JWT, not PAT). The preference itself is read by the service layer on every invoice POST. There's no separate public endpoint for it because org-level settings are an admin action.

How it works

When auto-round is on, the service computes the total as:

pre   = subtotal − discount + tax + shipping + adjustment − tds
total = round(pre)                # via the chosen method
round_off = total − pre            # posted to Round Off ledger

The grand total stamped on the invoice is the whole rupee. The round_off field carries the delta — positive means we rounded up (income to the org), negative means we rounded down (small expense).

Rounding methods

MethodBehaviourExample (₹199.49 → ?)
nearest (default)Half-up. .50 rounds to +1; .49 rounds to +0.₹199
upCeiling. Any fractional rupee rounds up.₹200
downFloor. Any fractional rupee rounds down.₹199

“Nearest” uses half-up rounding (Indian accounting convention), not Python's banker's rounding which would send 0.5 to the nearest even integer. We pick the convention that matches what your accountant expects.

Caller override on POST /invoices

If the caller passes round_off explicitly, that value wins — auto-round only fires when the field is omitted (null).

# Org pref is on, but caller forces no rounding:
POST /invoices
{ ..., "round_off": 0,    ... }     // → stays fractional

# Org pref is on, caller leaves to auto:
POST /invoices
{ ..., (no round_off)     ... }     // → auto-rounded

# Org pref is off, caller forces a specific adjustment:
POST /invoices
{ ..., "round_off": -0.50 ... }     // → applied verbatim

Journal entry

When the invoice is approved, the JE includes a Round Off line:

# Example: ₹199.43 line + 18% GST
# pre-round total = ₹235.33; auto-rounded to ₹235

Dr Accounts Receivable         235.00
   Cr Sales (revenue)          199.43
   Cr Output CGST               17.95
   Cr Output SGST               17.95
   Cr Round Off (income)         0.33     ← here

The Round Off ledger is auto-resolved by name (case-insensitive match on “Round Off” / “Rounding”). If the org doesn't have such an account configured, the round-off line is skipped silently and the total still balances (the rounded total absorbs it). Best practice: create a Round Off account under Chart of Accounts the first time you turn the feature on.

Update / re-edit path

When you edit a draft invoice (lines or header amounts), the service recomputes round_off from scratch if the previously-stored value looks auto-computed (|round_off| < 1). Manual large overrides are preserved. The math is consistent regardless of which path you used to create the invoice.

What about bills?

Bills have a round_offcolumn but no auto-round preference yet — vendors send you fixed-amount bills, not items you derive a total from, so the math doesn't drift the same way. You can still pass a manual round_off on POST /billsif you need to match a vendor's rounded total exactly.

Cookbook

Detecting whether the org has auto-round on

# Internal API only (admin action)
curl -H "X-Org-Id: $ORG" -H "X-User-Id: $USER" \
  https://app.finzbooks.com/api-py/api/v1/organisations/$ORG/preferences

# → { "success": true, "preferences": { "roundInvoiceTotals": true, ... } }

Forcing no round-off on a one-off invoice

Pass round_off: 0 explicitly — the caller value wins even when the org pref is on.

Migrating: applying round-off to historical invoices

Existing invoices are not retroactively rounded — auto-round only fires on create + update. To clean up historical fractional totals, run an update on each (a PATCH with no body changes still re-evaluates round_off if the helper detects a previously auto- computed value).