Rent automation
Once a lease is signed, Kuberan should handle every monthly rent invoice without anyone clicking anything. The automation has three moving parts that most of the time you never think about — but understanding them is useful when an invoice doesn’t show up on the 1st, or when a rent change doesn’t apply.
The three moving parts
1. RentSchedule rows
The moment you save a lease, the server materialises a RentSchedule row for every period in the lease term at the current baseRent. For a 12-month monthly lease starting March 1, 2026: twelve rows, each with periodStart, periodEnd, dueDate, amount, status='pending', invoiceId=null.
For month-to-month leases (no endDate), the schedule materialises 24 months ahead. The cron extends the window as needed.
2. The monthly invoice cron
On the 1st of every month at 04:00 server time, generateInvoicesFromSchedule runs for every client with propertiesEnabled=true. For each RentSchedule row where dueDate <= today and status='pending' and invoiceId=null, it:
- Creates a draft Invoice addressed to the lease’s shadow Customer.
- Adds a single line item: rent income account, amount from the RentSchedule row, tagged with
propertyId/unitId/leaseId. - Auto-exempts HST/GST if the property type is
residential. - Saves the invoice and writes its ID back to the RentSchedule row’s
invoiceId, flippingstatustoinvoiced.
The JE helper is idempotent on (sourceType, sourceId) — running the cron twice in a row doesn’t create duplicate invoices.
If the AR / revenue JE fails to post (rare — usually a missing account default), the RentSchedule row is left at pending so the next run can retry. The invoice is not created.
3. Scheduled escalations
Pre-planned bumps written into the lease at signing (“3% on each anniversary”) live on lease.escalations as an array. Each entry has type, value, effectiveDate, status.
On every daily run (03:05), applyScheduledEscalations sweeps leases where any escalation has status='scheduled' and effectiveDate <= today. For each:
- Computes the new baseRent from
type + value(fixed-amount adds dollars, percentage multiplies, manual is absolute, cpi-linked is percentage-equivalent). - Updates
lease.baseRent. - Stamps the escalation entry with
status='applied'andnewBaseRent. - Reprices every RentSchedule row where
status='pending'andinvoiceId=nullto the new amount.
Already-invoiced rows are never re-priced — history is immutable. Only unissued future rows move.
If a lease has multiple past-due escalations (the cron was off for a while), they apply in effectiveDate order so each successive computation sees the rent bumped by the prior escalation.
Verifying automation is working
End-to-end check for a single lease:
- Open the Lease detail.
- Rent Schedule tab — confirm rows exist, amounts match the current baseRent, and dueDates line up with the frequency.
- Click Generate next invoice. A draft Invoice should be created. Open it.
- On the Invoice, check line 1 has the right property/unit/lease tags and HST is zero for residential.
- Back on the Lease, look at Rent History — any past escalations should show up here with their applied date.
If the generate button does nothing, the invoice failed to post — usually a missing COA default. Check Settings → Property account defaults and re-run the COA wizard.
What to do when an invoice doesn’t show up on the 1st
Most likely cause: client feature flag off. Check client.features.propertiesEnabled — the cron filter excludes clients who haven’t opted in.
Next most likely: the RentSchedule row already had invoiceId set (invoice was created manually, or by a prior run) and you don’t realise it. Look at the Rent Schedule tab for the row’s status.
After that: the JE failed. Usually visible in the server logs; the row stays pending and retries on the next daily run rather than the next monthly one (rent cron is daily in practice — the 1st is just the typical date new rows become due).
What to do when an escalation doesn’t apply
Confirm the escalation’s status is scheduled and effectiveDate is in the past. If either is wrong, fix it on the Lease detail and it’ll pick up on the next daily run.
If the cron itself isn’t running (server restart, maintenance window), you can trigger a single-lease apply via the Rent History tab.
Manually re-issuing a single invoice
Sometimes you need to bump a single period’s invoice through out-of-band — e.g. the monthly cron was down and you want to catch up a specific tenant.
- Open the Lease detail → Rent Schedule tab.
- Find the row for the period you want to invoice.
- Click Generate next invoice at the top of the tab. It operates on the oldest pending row first; repeat to catch up multiple periods.