This commit is contained in:
gsinghpal
2026-04-24 21:04:38 -04:00
parent 0eab4b4efb
commit 41d0908ade
4083 changed files with 1230780 additions and 287 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating — Configurator',
'version': '19.0.14.0.0',
'version': '19.0.14.2.0',
'category': 'Manufacturing/Plating',
'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.',
'description': """

View File

@@ -347,40 +347,20 @@ class SaleOrder(models.Model):
}
# ---- Quick-nav counts for smart buttons (Phase D9 / D14) ----
x_fc_invoice_count = fields.Integer(
string='Invoices', compute='_compute_nav_counts',
)
x_fc_ncr_count = fields.Integer(
string='NCRs', compute='_compute_nav_counts',
)
x_fc_picking_count = fields.Integer(
string='Pickings', compute='_compute_nav_counts',
)
x_fc_attachment_count = fields.Integer(
string='Files', compute='_compute_nav_counts',
string='Transfer Count', compute='_compute_nav_counts',
)
@api.depends('invoice_ids', 'picking_ids')
@api.depends('picking_ids')
def _compute_nav_counts(self):
# Invoice + picking counts are cheap (related collections).
for rec in self:
rec.x_fc_invoice_count = len(rec.invoice_ids)
rec.x_fc_picking_count = len(rec.picking_ids)
# Attachment counts — batched read_group.
ids = self.ids
att_counts = {}
if ids:
rows = self.env['ir.attachment'].sudo().read_group(
[('res_model', '=', 'sale.order'),
('res_id', 'in', ids)],
['res_id'], ['res_id'], lazy=False,
)
att_counts = {r['res_id']: r['__count'] for r in rows}
for rec in self:
rec.x_fc_attachment_count = att_counts.get(rec.id, 0)
# NCR counts — only if the module is installed.
ids = self.ids
NCR = self.env.get('fusion.plating.ncr')
ncr_counts = {}
if ids and NCR is not None and 'sale_order_id' in NCR._fields:
@@ -396,21 +376,11 @@ class SaleOrder(models.Model):
for rec in self:
rec.x_fc_ncr_count = ncr_counts.get(rec.id, 0)
def action_view_invoices(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Invoices',
'res_model': 'account.move',
'view_mode': 'list,form',
'domain': [('id', 'in', self.invoice_ids.ids)],
}
def action_view_pickings(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Deliveries / Pickings',
'name': 'Transfers',
'res_model': 'stock.picking',
'view_mode': 'list,form',
'domain': [('id', 'in', self.picking_ids.ids)],
@@ -426,22 +396,6 @@ class SaleOrder(models.Model):
'domain': [('sale_order_id', '=', self.id)],
}
def action_view_files(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Files',
'res_model': 'ir.attachment',
'view_mode': 'kanban,list,form',
'domain': [
('res_model', '=', 'sale.order'),
('res_id', '=', self.id),
],
'context': {
'default_res_model': 'sale.order',
'default_res_id': self.id,
},
}
def action_view_bom_items(self):
"""Open SO lines grouped by part catalog (Phase D2)."""

View File

@@ -12,17 +12,16 @@
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button name="action_view_rfq"
type="object"
class="oe_stat_button"
icon="fa-envelope-o"
invisible="not x_fc_rfq_attachment_id">
<div class="o_stat_info">
<span class="o_stat_value">1</span>
<span class="o_stat_text">RFQ</span>
</div>
</button>
<!-- Hide standard Delivery button: our Transfers button (below) shows
all stock.picking records - inbound receipts AND outbound deliveries -
which matches the plating workflow better than outbound-only. -->
<xpath expr="//button[@name='action_view_delivery']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<!-- Insert before standard Invoices: PO, then RFQ (multiple position="before"
stack so last-inserted ends up closest to anchor; order here is PO, RFQ). -->
<xpath expr="//button[@name='action_view_invoice']" position="before">
<button name="action_view_po"
type="object"
class="oe_stat_button"
@@ -33,6 +32,33 @@
<span class="o_stat_text">PO</span>
</div>
</button>
<button name="action_view_rfq"
type="object"
class="oe_stat_button"
icon="fa-envelope-o"
invisible="not x_fc_rfq_attachment_id">
<div class="o_stat_info">
<span class="o_stat_value">1</span>
<span class="o_stat_text">RFQ</span>
</div>
</button>
</xpath>
<!-- After standard Invoices: Transfers (all stock.picking for this SO). -->
<xpath expr="//button[@name='action_view_invoice']" position="after">
<button name="action_view_pickings"
type="object"
class="oe_stat_button"
icon="fa-truck"
invisible="x_fc_picking_count == 0">
<field name="x_fc_picking_count" widget="statinfo"
string="Transfers"/>
</button>
</xpath>
<!-- After standard Manufacturing: Active WOs, NCRs, Files, BOM Items, By WO.
BOM Items and By WO are last so Odoo's button box overflows them into More. -->
<xpath expr="//button[@name='action_view_mrp_production']" position="after">
<button name="action_view_workorders"
type="object"
class="oe_stat_button"
@@ -41,22 +67,6 @@
<field name="x_fc_workorder_count" widget="statinfo"
string="Active WOs"/>
</button>
<button name="action_view_invoices"
type="object"
class="oe_stat_button"
icon="fa-file-text-o"
invisible="x_fc_invoice_count == 0">
<field name="x_fc_invoice_count" widget="statinfo"
string="Invoices"/>
</button>
<button name="action_view_pickings"
type="object"
class="oe_stat_button"
icon="fa-truck"
invisible="x_fc_picking_count == 0">
<field name="x_fc_picking_count" widget="statinfo"
string="Pickings"/>
</button>
<button name="action_view_ncrs"
type="object"
class="oe_stat_button"
@@ -65,14 +75,6 @@
<field name="x_fc_ncr_count" widget="statinfo"
string="NCRs"/>
</button>
<button name="action_view_files"
type="object"
class="oe_stat_button"
icon="fa-paperclip"
invisible="x_fc_attachment_count == 0">
<field name="x_fc_attachment_count" widget="statinfo"
string="Files"/>
</button>
<button name="action_view_bom_items"
type="object"
class="oe_stat_button"