fix(billing): skip zero-amount invoices (no lines) — drop empty move, don't post nothing
This commit is contained in:
@@ -120,6 +120,15 @@ class TestLedgerIngest(TransactionCase):
|
|||||||
self.assertAlmostEqual(mv.amount_untaxed, 200.0, places=2) # captured via reconciling line
|
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))
|
self.assertTrue(any('base/unitemized' in (l.name or '') for l in mv.invoice_line_ids))
|
||||||
|
|
||||||
|
def test_zero_amount_invoice_skipped(self):
|
||||||
|
data = [{'id': 'inv-zero', 'stripe_invoice_id': 'in_z', 'invoice_number': 'NEX-ZERO',
|
||||||
|
'user_external_id': 'u-1', 'partner_name': 'Acme', 'partner_email': 'ar@acme.test',
|
||||||
|
'invoice_date': '2026-05-01', 'currency': 'CAD', 'status': 'paid',
|
||||||
|
'subtotal': 0.0, 'tax': 0.0, 'amount_paid': 0.0, 'paid_at': None, 'items': []}]
|
||||||
|
summary = self.W._ingest_invoices(data, post=False)
|
||||||
|
self.assertFalse(self.Move.search([('x_fc_nexacloud_invoice_id', '=', 'inv-zero')]))
|
||||||
|
self.assertTrue(any(s.get('reason') == 'zero-amount invoice' for s in summary['skipped']))
|
||||||
|
|
||||||
def test_post_and_reconcile_paid_only(self):
|
def test_post_and_reconcile_paid_only(self):
|
||||||
base = _inv_fixture()[0]
|
base = _inv_fixture()[0]
|
||||||
paid = dict(base, id='inv-paid', invoice_number='NEX-PAID',
|
paid = dict(base, id='inv-paid', invoice_number='NEX-PAID',
|
||||||
|
|||||||
@@ -171,6 +171,12 @@ class FusionBillingInvoiceLedgerWizard(models.TransientModel):
|
|||||||
"account_id": self._fc_income_account("base").id,
|
"account_id": self._fc_income_account("base").id,
|
||||||
"tax_ids": [(6, 0, tax.ids)] if tax else [(5, 0, 0)],
|
"tax_ids": [(6, 0, tax.ids)] if tax else [(5, 0, 0)],
|
||||||
}))
|
}))
|
||||||
|
if not line_vals:
|
||||||
|
# zero-amount invoice (no items, $0 subtotal) — nothing to record;
|
||||||
|
# drop the empty move (whether just-created or a pre-existing draft).
|
||||||
|
move.unlink()
|
||||||
|
summary["skipped"].append({"id": nc_id, "reason": "zero-amount invoice"})
|
||||||
|
continue
|
||||||
move.write({"invoice_line_ids": line_vals})
|
move.write({"invoice_line_ids": line_vals})
|
||||||
summary["updated" if existing else "created"] += 1
|
summary["updated" if existing else "created"] += 1
|
||||||
if post:
|
if post:
|
||||||
@@ -213,7 +219,7 @@ class FusionBillingInvoiceLedgerWizard(models.TransientModel):
|
|||||||
continue
|
continue
|
||||||
mv = Move.search([("x_fc_nexacloud_invoice_id", "=", nc_id),
|
mv = Move.search([("x_fc_nexacloud_invoice_id", "=", nc_id),
|
||||||
("move_type", "=", "out_invoice")], limit=1)
|
("move_type", "=", "out_invoice")], limit=1)
|
||||||
if not mv:
|
if not mv or not mv.invoice_line_ids:
|
||||||
summary["skipped_missing"] += 1
|
summary["skipped_missing"] += 1
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user