Files
Odoo-Modules/fusion_plating/fusion_plating_quality/controllers/fp_quality_dashboard.py
gsinghpal c00831a72a feat(quality_dashboard): sixth 'Certificates' tab (Tasks 14-16)
Counts endpoint: certificates block — open=draft, overdue=draft+>24h.
Falls back to {open:0, overdue:0} when fp.certificate isn't installed.

JS: TABS array gains the 6th entry. Existing data-driven OWL template
auto-renders both the header tile and the body panel. Tab opens the
fp.certificate kanban grouped by state, filtered to draft by default.

Deep-link: setup() reads action.context.params.tab. The
cert_awaiting_issuance notification email links to
/odoo/action-fp_quality_dashboard?tab=certificates and lands the QM
on the right tab automatically.

Template: 'Open across all 5' → 'Open across all <tabs.length>' so
it stays correct if more tabs are added later.

Manifest: fusion_plating_quality 19.0.6.6.6 → 19.0.7.0.0
(fusion_plating_certificates already in depends — no change needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:49:10 -04:00

101 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
#
# Sub 12 Phase D — counts endpoint for the Unified Quality Dashboard.
from odoo import fields, http
from odoo.http import request
class FpQualityDashboardController(http.Controller):
@http.route('/fp/quality/dashboard/counts',
type='jsonrpc', auth='user', methods=['POST'])
def counts(self):
"""Return per-tab open + overdue counts for the dashboard.
"Overdue" definition:
- Hold: state='on_hold' for > 3 days
- Check: state='pending' for > 1 day
- NCR: state in (open, containment, disposition) AND reported >7d
- CAPA: due_date < today AND state not in (effective, closed)
- RMA: state='received' for > 5 days (triage past due) OR
state in (authorised, shipped_to_us) for > 14 days
- Certificate: state='draft' for > 1 day (spec 2026-05-25)
"""
env = request.env
today = fields.Date.context_today(env.user)
now = fields.Datetime.now()
Hold = env['fusion.plating.quality.hold']
Check = env['fusion.plating.quality.check']
Ncr = env['fusion.plating.ncr']
Capa = env['fusion.plating.capa']
Rma = env['fusion.plating.rma']
Cert = env['fp.certificate'] if 'fp.certificate' in env else None
d3 = fields.Datetime.subtract(now, days=3)
d1 = fields.Datetime.subtract(now, days=1)
d7 = fields.Datetime.subtract(now, days=7)
d5 = fields.Datetime.subtract(now, days=5)
d14 = fields.Datetime.subtract(now, days=14)
return {
'holds': {
'open': Hold.search_count(
[('state', 'in', ('on_hold', 'under_review'))]),
'overdue': Hold.search_count([
('state', 'in', ('on_hold', 'under_review')),
('create_date', '<', d3),
]),
},
'checks': {
'open': Check.search_count([('state', '=', 'pending')]),
'overdue': Check.search_count([
('state', '=', 'pending'),
('create_date', '<', d1),
]),
},
'ncrs': {
'open': Ncr.search_count([
('state', 'in', ('open', 'containment', 'disposition')),
]),
'overdue': Ncr.search_count([
('state', 'in', ('open', 'containment', 'disposition')),
('reported_date', '<', d7),
]),
},
'capas': {
'open': Capa.search_count([
('state', 'not in', ('effective', 'closed')),
]),
'overdue': Capa.search_count([
('state', 'not in', ('effective', 'closed')),
('due_date', '<', today),
('due_date', '!=', False),
]),
},
'rmas': {
'open': Rma.search_count([
('state', 'not in', ('closed', 'cancelled')),
]),
'overdue': Rma.search_count([
'|',
'&', ('state', '=', 'received'),
('create_date', '<', d5),
'&', ('state', 'in', ('authorised', 'shipped_to_us')),
('create_date', '<', d14),
]),
},
# Spec 2026-05-25 — Certificates tab
'certificates': ({
'open': Cert.search_count([('state', '=', 'draft')]),
'overdue': Cert.search_count([
('state', '=', 'draft'),
('create_date', '<', d1),
]),
} if Cert is not None else {'open': 0, 'overdue': 0}),
}