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.
This commit is contained in:
@@ -107,6 +107,19 @@ class TestLedgerIngest(TransactionCase):
|
||||
with self.assertRaises(UserError):
|
||||
self.W._read_nexacloud_invoices()
|
||||
|
||||
def test_unitemized_subtotal_gets_reconciling_line(self):
|
||||
data = [{
|
||||
'id': 'inv-base', 'stripe_invoice_id': 'in_base', 'invoice_number': 'NEX-BASE',
|
||||
'user_external_id': 'u-2', 'partner_name': 'Globex', 'partner_email': 'ops@globex.test',
|
||||
'invoice_date': '2026-05-01', 'currency': 'CAD', 'status': 'open',
|
||||
'subtotal': 200.0, 'tax': 0.0, 'amount_paid': 0.0, 'paid_at': None,
|
||||
'items': [], # base plan billed via Stripe only — no line items
|
||||
}]
|
||||
self.W._ingest_invoices(data, post=False)
|
||||
mv = self.Move.search([('x_fc_nexacloud_invoice_id', '=', 'inv-base')])
|
||||
self.assertAlmostEqual(mv.amount_untaxed, 200.0, places=2) # captured via reconciling line
|
||||
self.assertTrue(any('base/unitemized' in (l.name or '') for l in mv.invoice_line_ids))
|
||||
|
||||
def test_prune_shadow_removes_shadow_subs_only(self):
|
||||
p = self.env['res.partner'].sudo().create({'name': 'X'})
|
||||
shadow = self.env['sale.order'].sudo().create({'partner_id': p.id, 'x_fc_shadow': True})
|
||||
|
||||
Reference in New Issue
Block a user