feat(quality_dashboard): manifest bump + battle test (Tasks 7-8)

Version 19.0.7.0.0 → 19.0.8.0.0 (triggers asset cache invalidation
on -u so the new template + SCSS load cleanly).

Battle test script: 6-check entech smoke. Validates snapshot shape,
canonical section order, required section keys, open_kanban_xmlid
resolves to act_window, banner item shape when items exist. Summary
prints per-section counts so you can eyeball the entech state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-25 12:25:31 -04:00
parent 547e7d66a9
commit c8db3915ea
2 changed files with 85 additions and 1 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Quality (QMS)',
'version': '19.0.7.0.0',
'version': '19.0.8.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Native QMS for plating shops: NCR, CAPA, calibration, AVL, FAIR, '
'internal audits, customer specs, document control. CE + EE compatible.',

View File

@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
"""Quality Dashboard redesign — entech smoke.
Spec: docs/superpowers/specs/2026-05-25-quality-dashboard-redesign-design.md
Plan: docs/superpowers/plans/2026-05-25-quality-dashboard-redesign-plan.md
Run on entech via odoo-shell:
ssh pve-worker5 "pct exec 111 -- bash -c 'echo \\\"
exec(open(\\\\\\\"/mnt/extra-addons/custom/fusion_plating_quality/scripts/bt_quality_dashboard_redesign.py\\\\\\\").read())
\\\" | su - odoo -s /bin/bash -c \\\"/usr/bin/odoo shell -c /etc/odoo/odoo.conf -d admin --no-http\\\"'"
Validates:
1. FpQualityDashboardSnapshot helper class exists and builds
2. Response shape (banner + sections + computed_at)
3. Section order is canonical (cert, hold, ncr, rma, capa, check)
4. Each section has all required keys
5. Each section's open_kanban_xmlid resolves to a real act_window
6. Banner items shape includes open_action that resolves to a model
"""
from odoo.addons.fusion_plating_quality.controllers.fp_quality_dashboard \
import FpQualityDashboardSnapshot, SECTION_ORDER
def _ok(cond, label):
if cond:
print('OK -', label)
else:
print('FAIL -', label)
raise SystemExit(1)
# ---- 1. Build snapshot ----
snap = FpQualityDashboardSnapshot(env).build()
_ok(isinstance(snap, dict), 'snapshot is a dict')
# ---- 2. Response shape ----
for k in ('banner', 'sections', 'computed_at'):
_ok(k in snap, f'snapshot has key {k!r}')
_ok(isinstance(snap['sections'], list), 'sections is a list')
_ok(isinstance(snap['banner'], dict), 'banner is a dict')
# ---- 3. Section order ----
types = [s['type'] for s in snap['sections']]
canonical_present = [t for t in SECTION_ORDER if t in types]
_ok(types == canonical_present,
f'section order canonical: got {types}, expected subset of {SECTION_ORDER}')
# ---- 4. Section keys ----
for sec in snap['sections']:
for k in ('type', 'label', 'icon', 'open', 'overdue', 'items',
'open_kanban_xmlid'):
_ok(k in sec, f'section {sec["type"]} has key {k!r}')
# ---- 5. open_kanban_xmlid resolves ----
for sec in snap['sections']:
try:
act = env.ref(sec['open_kanban_xmlid'], raise_if_not_found=False)
_ok(bool(act), f'section {sec["type"]} kanban xmlid resolves')
except Exception as e:
_ok(False, f'section {sec["type"]} xmlid: {e}')
# ---- 6. Banner items shape ----
print(f' banner.all_clear = {snap["banner"]["all_clear"]}')
print(f' banner.items = {len(snap["banner"]["items"])}')
print(f' banner.total_matching = {snap["banner"]["total_matching"]}')
if snap['banner']['items']:
item = snap['banner']['items'][0]
for k in ('type', 'id', 'name', 'customer', 'subtitle',
'urgency', 'critical_badge', 'open_action'):
_ok(k in item, f'banner item has key {k!r}')
# open_action.res_model resolves to a model
_ok(item['open_action']['res_model'] in env,
f'banner item res_model {item["open_action"]["res_model"]!r} is installed')
# ---- Summary ----
print()
print('--- bt_quality_dashboard_redesign: ALL PASS ---')
print(f' Sections present: {len(snap["sections"])}')
for sec in snap['sections']:
print(f' {sec["icon"]} {sec["label"]}: {sec["open"]} open '
f'({sec["overdue"]} overdue), top-{len(sec["items"])} listed')
print(f' Banner: {len(snap["banner"]["items"])} items '
f'(of {snap["banner"]["total_matching"]} matching), '
f'all_clear={snap["banner"]["all_clear"]}')