Skip to content
All work

Financial Automation

Automated Billing & Tax Engine

Unattended recurring billing — scheduled worker services that generate invoices, calculate tax through Avalara AvaTax, and post to SAP Business One with idempotent, replay-safe runs.

Context

Recurring customer billing was a manual, error-prone monthly exercise: staff generated invoices by hand in the ERP, applied tax rules themselves, and reconciled mistakes after the fact. The goal was to make the entire cycle — invoice generation, tax calculation, posting, reporting — run unattended.

Constraints

  • This code moves money. A duplicate invoice or a missed one is not a bug ticket, it is a customer-facing financial error.
  • Tax rules vary by jurisdiction and change constantly — encoding them in-house was a permanent correctness liability.
  • Runs happen on schedules against external systems (ERP, tax API) that can be slow, down, or mid-maintenance; partial failure is the normal case to design for, not the exception.

Architecture

idempotency keys · retry state Scheduler .NET Worker Service Billing Engine recurring runs · rules Avalara AvaTax tax calculation SAP B1 invoice posted SQL Server billing state
At-least-once execution: every posting is idempotent, so an interrupted run replays safely without double-billing.

A .NET Worker Service triggers billing runs on schedule. The billing engine evaluates recurring billing rules, calls Avalara AvaTax for jurisdiction-correct tax on each invoice, and posts the result to SAP Business One. Every step records its state in SQL Server keyed by an idempotency key, so a run that dies midway — network fault, ERP maintenance window, deploy — simply replays: already-posted invoices are skipped, unfinished ones complete.

Decisions & Trade-offs

  • At-least-once with idempotent posting, not exactly-once. Exactly-once delivery across a scheduler, a tax API, and an ERP is a fiction; idempotency keys make retries safe and turn “did it run twice?” into a non-question.
  • Delegating tax to AvaTax over in-house tax tables. An external dependency and per-call cost, in exchange for jurisdiction changes being someone else’s full-time job. For tax, buy beats build.
  • Reconciliation as a feature, not an afterthought. Custom reports compare what the engine believes it billed against what the ERP posted — automation that finance can verify is automation that finance trusts.

Impact

Recurring billing became a background process instead of a monthly project: invoices generate, tax calculates, and postings land in the ERP without human touch, with reconciliation reports as the safety net. The same idempotent-run pattern was reused for the platform’s other automation — data migration jobs and scheduled financial reporting.

Next case · Applied Cryptography

Secure NFC e-Prescription System