Periodic billing projects are the long-running customer engagements where the same invoice goes out month after month: consulting retainers, SaaS subscriptions, equipment leases, cleaning contracts. The Netorigo Finance module handles them in a project table with schedule, milestones, dunning, and a direct hookup into the NAV invoicing pipeline.
Use cases
The most common types we see:
-
Consulting retainer — a fixed monthly amount (800,000 HUF a month, say) buying access to a specific consultant or capacity bucket. The client pays for availability; actual utilisation varies.
-
SaaS subscription — monthly or annual, often tiered (Basic, Pro, Enterprise). When wired up with the Netorigo Sales module, tier changes automatically reprice the next invoice.
-
Equipment lease — copier rental, robot rental, vehicle fleet. Fixed monthly fee plus optional usage-based surcharges (page counter, odometer).
-
Cleaning or maintenance contract — flat monthly retainer plus the occasional out-of-scope job.
Project shape
Each project is a project row carrying:
- partner FK
- customer-side contract identifier
- start and end date (or open-ended)
- schedule rule (cron-style): first of each month, first working day of each quarter, etc.
- base fee (amount plus currency)
- extra-line rules (usage-based, milestone-based)
- responsible parties (account manager, technical owner)
- dunning rule (when to send a reminder, when to escalate)
A project_invoice table holds the issued invoices, keyed back to the project. A project_milestone table holds delivery milestones for milestone-billed projects.
The state machine
Every project moves through a five-state machine: DRAFT → ACTIVE → PAUSED → COMPLETED → ARCHIVED.
- DRAFT: not yet started. Contract negotiation phase. No invoicing.
- ACTIVE: running. Invoices are generated on the schedule.
- PAUSED: temporarily halted (summer shutdown, mid-cancellation). Invoicing stops, the project does not move to ARCHIVED.
- COMPLETED: contract reached its end, all deliverables met.
- ARCHIVED: post-completion, retained for audit purposes, not eligible for further write operations.
Every state transition is audited in a project_audit table: who, when, why (commit-message style). The transition to ARCHIVED is only permitted six months after COMPLETED to keep the simplified Hungarian audit-aging window clean.
Automated NAV invoicing
A project-billing.worker.ts BullMQ cron fires on the schedule (every 1st of the month at 06:00, for example), looks up projects due that day, and generates an invoice draft for each one. Projects marked auto-approve: true get the draft auto-approved and pushed into the NAV uploader queue immediately. The monthly billing cycle runs without human intervention.
One partner — a consulting firm with 84 active projects — used to spend six hours every month on billing work: walking the project list, updating statuses, copying to Excel, sending PDFs. The new flow takes two minutes (just reviewing the generated invoices for anomalies, approving, sending). That is five hours and 58 minutes recovered per month.
Why the state machine is audit-friendly
Why do we not allow ACTIVE → DRAFT? Because an ACTIVE project has already issued invoices, and reverting to DRAFT would muddy whether those invoices have a binding contract behind them. Hungarian audit rules require that every issued invoice have a definite legal basis.
If a project must be unwound, the proper path is the STORNO sequence: issue a STORNO invoice for every prior invoice, move the project to PAUSED, then to COMPLETED. This preserves the audit chain. Skipping back to DRAFT would break it.
Periodic billing is not a flashy module, but for a service business it absorbs about six hours a month that nobody enjoys. Across 84 projects that is 72 hours of recovered capacity per year — and a billing cycle that never slips because someone went on holiday.