fix(billing): importer review fixes — surface failures, validate, dedupe
Resolves findings from the post-build review: - C1: a partial import was indistinguishable from success. action_run_import now logs failed rows at ERROR (survives nexa's log_level=warn) and the wizard shows red/amber banners with failed/skipped counts. - H3: an unrecognized billing_cycle silently fell back to monthly (wrong plan AND price). Now raised per-row -> failed[], never silently mis-billed. - M5: a NULL plan price silently became a $0 line. Prices now preserve NULL-vs-0.0; a missing price for the subscription's cycle is failed[]. - H2: post-connect query/schema errors now become a clean UserError, not a raw SQL traceback (matches the connection-error path). - M4: per-row failures now record the exception type and log a traceback. - MED#3: charge plan_id set explicitly False so re-runs re-assert the shadow-safe NULL even if it was changed between runs. - HIGH-edge: re-run only rewrites x_fc_* on existing subs; partner_id/plan_id/ line are set at creation only (never rewrite immutable fields). - account_link: partner email match is now case-insensitive (=ilike) to avoid duplicate partners against a differently-cased pre-existing partner. Shadow-safety invariant unchanged and re-confirmed. 52/52 green on odoo-trial.
This commit is contained in:
@@ -211,6 +211,29 @@ class TestImporterErrorIsolation(TransactionCase):
|
||||
self.assertTrue(summary['failed'], "the bad row must be recorded in failed[]")
|
||||
self.assertTrue(any(f['kind'] == 'user' for f in summary['failed']))
|
||||
|
||||
def test_unknown_billing_cycle_is_failed_not_silently_monthly(self):
|
||||
data = _fixture()
|
||||
data['subscriptions'][0]['billing_cycle'] = 'annual' # not monthly/yearly
|
||||
summary = self.Wizard._import_rows(data)
|
||||
self.assertFalse(self.env['sale.order'].search(
|
||||
[('x_fc_nexacloud_subscription_id', '=', 's-1')]),
|
||||
"an unrecognized billing_cycle must NOT silently create a monthly sub")
|
||||
self.assertTrue(any(f['kind'] == 'subscription' and f['id'] == 's-1'
|
||||
for f in summary['failed']))
|
||||
|
||||
def test_missing_price_for_cycle_is_failed_not_zero(self):
|
||||
data = _fixture()
|
||||
data['plans'][0]['price_yearly'] = None # s-2 is yearly -> no price for it
|
||||
summary = self.Wizard._import_rows(data)
|
||||
# the yearly sub fails (no silent $0 line); the monthly one still imports
|
||||
self.assertFalse(self.env['sale.order'].search(
|
||||
[('x_fc_nexacloud_subscription_id', '=', 's-2')]),
|
||||
"a missing price for the cycle must NOT silently create a $0 line")
|
||||
self.assertTrue(self.env['sale.order'].search(
|
||||
[('x_fc_nexacloud_subscription_id', '=', 's-1')]))
|
||||
self.assertTrue(any(f['kind'] == 'subscription' and f['id'] == 's-2'
|
||||
for f in summary['failed']))
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestImporterReadGuard(TransactionCase):
|
||||
|
||||
Reference in New Issue
Block a user