Commit Graph

5 Commits

Author SHA1 Message Date
gsinghpal
95378ff1da fix(billing): skip zero-amount invoices (no lines) — drop empty move, don't post nothing 2026-05-27 17:33:36 -04:00
gsinghpal
c8529b8a99 feat(billing): post + reconcile only PAID invoices, keeping original dates
_post_and_reconcile_paid: for invoices NexaCloud marks paid, set the ledger
entry's invoice_date AND accounting date to the original NexaCloud date,
post, then reconcile the Stripe payment dated to the actual paid_at. Unpaid
invoices stay draft. Per-invoice isolated. 76 tests green on odoo-trial.
2026-05-27 17:29:41 -04:00
gsinghpal
7a66d7849d fix(billing): name ledger partners by company, not the NexaCloud user's full_name
One operator (e.g. "Gurpreet Singh") manages several distinct customer
businesses; naming partners from full_name mislabeled Mobility Specialties
Inc and Apex Vita Corporation as "Gurpreet Singh". Read the company field,
name the partner by company (mark is_company), and rewrite existing partners
so prior full_name-based names are corrected on re-ingest. 75 tests green.
2026-05-27 17:24:48 -04:00
gsinghpal
6b63df8c3d fix(billing): ledger live-run fixes — UUID cast, UTF-8, reconciling line
Surfaced by the nexamain dry-run against real data:
- reader: cast invoice_items.invoice_id::text (uuid = text[] mismatch).
- readers: set_client_encoding('UTF8') — invoice descriptions contain "×".
- ingest: add a balancing line when invoice.subtotal != sum(items). 9 paid
  base-plan invoices store the charge in subtotal with NO invoice_items, so
  itemized ingestion under-recorded revenue by ~$1,143 (37%); the reconciling
  line makes the Odoo invoice total match what Stripe billed.
74 tests green on odoo-trial.
2026-05-27 16:57:00 -04:00
gsinghpal
72d3130c88 feat(billing): NexaCloud invoice ledger — ingest invoices to account.move
Odoo becomes the accounting SoR by ingesting NexaCloud's real Stripe
invoices (read-only via the existing DSN) into native account.move
customer invoices: per-service-family income accounts, tax derived to
match the source invoice.tax, Stripe payments reconciled via
account.payment.register (invoice shows paid), idempotent on
x_fc_nexacloud_invoice_id, draft-first with bulk-post + a daily cron
(inactive). Plus a prune helper for the now-obsolete metered shadow data.
73 tests green on odoo-trial. Account codes use dots (Odoo 19 rejects '-').
2026-05-27 16:50:31 -04:00