fix(fusion_accounting_bank_rec): MV correctness for V19 schema + Odoo test harness

Three issues surfaced when running the MV smoke tests against westin-v19:

1. account_bank_statement_line has no `date` column in V19 — `date` is a
   related field flowing through move_id -> account_move.date. The MV
   now JOINs account_move and selects am.date.
2. is_reconciled is nullable; replace `= FALSE` with `IS NOT TRUE` so
   nulls (genuinely unreconciled lines that haven't had the compute run
   yet) are still included.
3. _refresh() now flushes the ORM cache (env.flush_all()) before the
   REFRESH so computed-stored fields like is_reconciled are written to
   the DB before the materialization snapshot reads them. Previously the
   reconcile-then-refresh path saw the pre-reconcile column value.
4. _trigger_mv_refresh() (suggestion create/write hook) now uses
   concurrently=False because Postgres forbids
   REFRESH MATERIALIZED VIEW CONCURRENTLY inside a transaction block,
   and Odoo's per-request cursor is always inside one. The cron path
   (Task 25) will open an autocommit cursor for CONCURRENTLY refreshes.
5. Tests dropped the env.cr.commit() pattern: Postgres always shows a
   transaction its own writes, so a non-CONCURRENTLY refresh in the
   same txn picks up freshly-inserted rows. Cleaner + works inside
   TransactionCase, which forbids cr.commit().

Verified: 4 new MV tests pass, 0 failures across 118 logical tests
(178 with parametrized property-based runs) of fusion_accounting_bank_rec
on westin-v19.

Made-with: Cursor
This commit is contained in:
gsinghpal
2026-04-19 11:51:02 -04:00
parent 12b6b46e2e
commit d953525758
4 changed files with 64 additions and 80 deletions

View File

@@ -120,10 +120,18 @@ class FusionReconcileSuggestion(models.Model):
return res
def _trigger_mv_refresh(self):
"""Best-effort MV refresh; never poison the originating transaction."""
"""Best-effort MV refresh; never poison the originating transaction.
Uses concurrently=False because Postgres forbids
REFRESH MATERIALIZED VIEW CONCURRENTLY inside a transaction block,
and Odoo's per-request cursor is always in a transaction. The cron
job (Task 25) opens a dedicated autocommit cursor for CONCURRENTLY
refreshes when the MV grows large enough that a brief blocking
refresh becomes objectionable.
"""
try:
self.env['fusion.unreconciled.bank.line.mv']._refresh(
concurrently=True)
concurrently=False)
except Exception as e: # noqa: BLE001
_logger.warning(
"MV refresh after suggestion write failed: %s", e)

View File

@@ -63,7 +63,12 @@ class FusionUnreconciledBankLineMV(models.Model):
REFRESH MATERIALIZED VIEW CONCURRENTLY (requires the unique index).
Falls back to a blocking refresh on the first refresh after creation
(when CONCURRENTLY is not yet allowed because the MV has never been
populated)."""
populated).
Flushes the ORM cache first so the materialization sees the latest
committed-to-DB values for fields like ``is_reconciled`` (computed,
stored — sometimes still buffered in the cache mid-request)."""
self.env.flush_all()
keyword = "CONCURRENTLY" if concurrently else ""
try:
self.env.cr.execute(