changes
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating — Quality (QMS)',
|
||||
'version': '19.0.6.2.0',
|
||||
'version': '19.0.6.6.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Native QMS for plating shops: NCR, CAPA, calibration, AVL, FAIR, '
|
||||
'internal audits, customer specs, document control. CE + EE compatible.',
|
||||
@@ -128,6 +128,10 @@ Copyright (c) 2026 Nexa Systems Inc. All rights reserved.
|
||||
'fusion_plating_quality/static/src/scss/fp_quality_dashboard.scss',
|
||||
'fusion_plating_quality/static/src/xml/fp_quality_dashboard.xml',
|
||||
'fusion_plating_quality/static/src/js/fp_quality_dashboard.js',
|
||||
# Contract Review flow — forced redirect into QA-005 after
|
||||
# an estimator creates a part under a toggle-on customer.
|
||||
# Pairs with the bus.bus push in fp_part_catalog.py:create.
|
||||
'fusion_plating_quality/static/src/js/contract_review_redirect.js',
|
||||
],
|
||||
},
|
||||
'installable': True,
|
||||
|
||||
@@ -23,11 +23,30 @@ class FpDirectOrderLine(models.Model):
|
||||
|
||||
@api.onchange('part_catalog_id')
|
||||
def _onchange_part_default_spec(self):
|
||||
"""Pre-fill the line's specification from the part's default."""
|
||||
"""Pre-fill the line's specification.
|
||||
|
||||
Priority (first non-empty result wins, matches the same
|
||||
"remember last entered" pattern used by process / unit_price /
|
||||
tax / thickness in the base wizard line):
|
||||
1. What the operator already typed on this line — never clobber
|
||||
2. Most recent SO line for (part, customer) where a spec
|
||||
was set — the "repeat order" carry-over
|
||||
3. Part's stored default — x_fc_default_customer_spec_id
|
||||
"""
|
||||
for rec in self:
|
||||
if (rec.part_catalog_id
|
||||
and rec.part_catalog_id.x_fc_default_customer_spec_id
|
||||
and not rec.customer_spec_id):
|
||||
if not rec.part_catalog_id or rec.customer_spec_id:
|
||||
continue
|
||||
partner = rec.wizard_id.partner_id if rec.wizard_id else False
|
||||
if partner:
|
||||
recent = self.env['sale.order.line'].search([
|
||||
('x_fc_part_catalog_id', '=', rec.part_catalog_id.id),
|
||||
('order_id.partner_id', '=', partner.id),
|
||||
('x_fc_customer_spec_id', '!=', False),
|
||||
], order='create_date desc', limit=1)
|
||||
if recent:
|
||||
rec.customer_spec_id = recent.x_fc_customer_spec_id
|
||||
continue
|
||||
if rec.part_catalog_id.x_fc_default_customer_spec_id:
|
||||
rec.customer_spec_id = (
|
||||
rec.part_catalog_id.x_fc_default_customer_spec_id
|
||||
)
|
||||
@@ -37,12 +56,22 @@ class FpDirectOrderWizard(models.Model):
|
||||
_inherit = 'fp.direct.order.wizard'
|
||||
|
||||
def action_create_order(self):
|
||||
"""Carry customer_spec_id from each wizard line to its SO line.
|
||||
"""Carry customer_spec_id from each wizard line to its SO line,
|
||||
and (when the operator opted in via push_to_defaults) save the
|
||||
spec back to the part as its new default so the next order
|
||||
auto-fills without relying on a SO-line history lookup.
|
||||
|
||||
The base method (in configurator) builds the SO with all the
|
||||
coating/treatment/process fields. We can't insert spec into the
|
||||
vals dict from here without a circular dep, so post-create we
|
||||
pair wizard lines to SO lines by sequence and patch.
|
||||
|
||||
The push-to-defaults block mirrors the base wizard's thickness
|
||||
push (action_create_order's "6. Push-to-defaults" loop) — spec
|
||||
lives here in the quality module so the back-write lives here
|
||||
too. Only fills when the part default is currently empty so we
|
||||
never clobber an existing default that the part-form user set
|
||||
explicitly.
|
||||
"""
|
||||
result = super().action_create_order()
|
||||
if self.sale_order_id:
|
||||
@@ -55,4 +84,15 @@ class FpDirectOrderWizard(models.Model):
|
||||
for wiz_line, so_line in zip(wiz_lines, so_lines):
|
||||
if wiz_line.customer_spec_id and not so_line.x_fc_customer_spec_id:
|
||||
so_line.x_fc_customer_spec_id = wiz_line.customer_spec_id.id
|
||||
# Spec push-to-default — only on first-time parts that
|
||||
# had the toggle auto-ticked (or manually ticked). Skip
|
||||
# one-off parts and parts that already have a default.
|
||||
if (wiz_line.push_to_defaults
|
||||
and not wiz_line.is_one_off
|
||||
and wiz_line.customer_spec_id
|
||||
and wiz_line.part_catalog_id
|
||||
and not wiz_line.part_catalog_id.x_fc_default_customer_spec_id):
|
||||
wiz_line.part_catalog_id.x_fc_default_customer_spec_id = (
|
||||
wiz_line.customer_spec_id.id
|
||||
)
|
||||
return result
|
||||
|
||||
@@ -208,11 +208,8 @@ class FpPartCatalog(models.Model):
|
||||
% part_label,
|
||||
'message': _(
|
||||
'Customer %(c)s requires a Contract Review '
|
||||
'(QA-005) on new parts. The review record '
|
||||
'has been pre-created — open it using the '
|
||||
'Contract Review smart button at the top '
|
||||
'of the part form, or from your Activities '
|
||||
'inbox.'
|
||||
'(QA-005) on new parts. Opening the review '
|
||||
'form now…'
|
||||
) % {'c': customer_label},
|
||||
'type': 'warning',
|
||||
'sticky': True,
|
||||
@@ -224,6 +221,30 @@ class FpPartCatalog(models.Model):
|
||||
'review notification', part.id, exc_info=True,
|
||||
)
|
||||
|
||||
# 3) Forced redirect into the QA-005 form. The frontend
|
||||
# listener (see fusion_plating_quality/static/src/js/
|
||||
# contract_review_redirect.js) intercepts this bus
|
||||
# notification and calls action.doAction() to navigate.
|
||||
# Rule 3 of the contract-review flow: customer-toggle-on
|
||||
# parts force the QA-005 to open right after save so the
|
||||
# estimator can complete (or visibly defer) the review
|
||||
# before moving on.
|
||||
try:
|
||||
Bus._sendone(
|
||||
self.env.user.partner_id,
|
||||
'fusion_plating.contract_review_redirect',
|
||||
{
|
||||
'review_id': review.id,
|
||||
'part_id': part.id,
|
||||
'part_label': part_label,
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
_logger.warning(
|
||||
'fp.part.catalog %s: could not push contract-'
|
||||
'review redirect bus message', part.id, exc_info=True,
|
||||
)
|
||||
|
||||
# ---- Actions -------------------------------------------------------------
|
||||
|
||||
def action_start_contract_review(self):
|
||||
|
||||
@@ -19,7 +19,7 @@ class ResCompany(models.Model):
|
||||
'res_company_qa_assistant_rel',
|
||||
'company_id',
|
||||
'user_id',
|
||||
string='QA Assistant Signers',
|
||||
string='Planning Signers',
|
||||
domain=[('share', '=', False)],
|
||||
help='Users authorised to sign Section 2.0 (Planning / Production '
|
||||
'Review) on a Contract Review. Plating Managers can sign '
|
||||
@@ -30,11 +30,13 @@ class ResCompany(models.Model):
|
||||
'res_company_qa_manager_rel',
|
||||
'company_id',
|
||||
'user_id',
|
||||
string='QA Manager Signers',
|
||||
string='QA Manager',
|
||||
domain=[('share', '=', False)],
|
||||
help='Users authorised to sign Section 3.0 (Quality Review) on a '
|
||||
'Contract Review. Plating Managers can sign regardless of '
|
||||
'this list.',
|
||||
help='QA Manager(s) for the shop. Signs Section 3.0 (Quality '
|
||||
'Review) on a Contract Review AND is the default Certified '
|
||||
'By signer on the Work Order Detail report (first user in '
|
||||
'the list is used for the cert signature). Plating Managers '
|
||||
'can sign Contract Reviews regardless of this list.',
|
||||
)
|
||||
|
||||
def _fp_get_qa_signers(self, section):
|
||||
|
||||
@@ -15,10 +15,10 @@ class ResConfigSettings(models.TransientModel):
|
||||
x_fc_qa_assistant_user_ids = fields.Many2many(
|
||||
related='company_id.x_fc_qa_assistant_user_ids',
|
||||
readonly=False,
|
||||
string='QA Assistant Signers',
|
||||
string='Planning Signers',
|
||||
)
|
||||
x_fc_qa_manager_user_ids = fields.Many2many(
|
||||
related='company_id.x_fc_qa_manager_user_ids',
|
||||
readonly=False,
|
||||
string='QA Manager Signers',
|
||||
string='QA Manager',
|
||||
)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/** @odoo-module **/
|
||||
/*
|
||||
* Copyright 2026 Nexa Systems Inc.
|
||||
* License OPL-1 (Odoo Proprietary License v1.0)
|
||||
* Part of the Fusion Plating product family.
|
||||
*
|
||||
* Forces the QA-005 Contract Review form to open right after an
|
||||
* estimator creates a new fp.part.catalog under a customer that has
|
||||
* x_fc_contract_review_required = True. Rule 3 of the contract-review
|
||||
* flow.
|
||||
*
|
||||
* Server side (fusion_plating_quality/models/fp_part_catalog.py):
|
||||
* after auto-creating the fp.contract.review record on part create,
|
||||
* push a bus notification of type "fusion_plating.contract_review_redirect"
|
||||
* with payload {review_id, part_id, part_label}.
|
||||
*
|
||||
* Frontend side (this file): a service subscribes to that bus type
|
||||
* on session start. When a payload arrives, dispatch an ir.actions.
|
||||
* act_window opening the review's form so the user lands on the QA-005
|
||||
* automatically. They can still close it and come back later — the
|
||||
* WO-step gate (rule 5) is the backstop.
|
||||
*/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
const contractReviewRedirectService = {
|
||||
dependencies: ["bus_service", "action"],
|
||||
start(env, { bus_service: bus, action }) {
|
||||
bus.subscribe(
|
||||
"fusion_plating.contract_review_redirect",
|
||||
(payload) => {
|
||||
if (!payload || !payload.review_id) {
|
||||
return;
|
||||
}
|
||||
action.doAction({
|
||||
type: "ir.actions.act_window",
|
||||
res_model: "fp.contract.review",
|
||||
res_id: payload.review_id,
|
||||
view_mode: "form",
|
||||
views: [[false, "form"]],
|
||||
target: "current",
|
||||
});
|
||||
},
|
||||
);
|
||||
bus.start();
|
||||
},
|
||||
};
|
||||
|
||||
registry
|
||||
.category("services")
|
||||
.add("fusion_plating_contract_review_redirect", contractReviewRedirectService);
|
||||
@@ -22,7 +22,7 @@
|
||||
permissions are affected. Plating Managers can
|
||||
always sign regardless of these lists.">
|
||||
<setting id="fp_qa_assistant_signers"
|
||||
string="QA Assistant Signers"
|
||||
string="Planning Signers"
|
||||
help="Users authorised to sign Section 2.0
|
||||
(Planning / Production Review). Typically
|
||||
one or two people. Leave empty if any
|
||||
@@ -33,10 +33,13 @@
|
||||
widget="many2many_tags"/>
|
||||
</setting>
|
||||
<setting id="fp_qa_manager_signers"
|
||||
string="QA Manager Signers"
|
||||
help="Users authorised to sign Section 3.0
|
||||
(Quality Review). Typically the QA
|
||||
Manager for the shop.">
|
||||
string="QA Manager"
|
||||
help="QA Manager(s) for the shop. Signs
|
||||
Section 3.0 (Quality Review) of the
|
||||
Contract Review, AND appears as the
|
||||
Certified By signer on the Work Order
|
||||
Detail report. The first user in the
|
||||
list is used for the cert signature.">
|
||||
<field name="x_fc_qa_manager_user_ids"
|
||||
widget="many2many_tags"/>
|
||||
</setting>
|
||||
|
||||
Reference in New Issue
Block a user