Standardise user-facing terminology across 5 modules (27 files):
- display_name compute: 'Work Order # 01368' -> 'WO # 01368'
- _description on 5 models: Plating Job{," Step"," Step Time Log"," Margin Report"," Recipe Node Override"} -> Work Order equivalents
- field labels (string=...) on 13 Many2one / One2many fields
across fp.batch, fp.thickness_reading, fp.quality.hold,
fp.job_consumption, fp.portal.job, fp.certificate, fp.delivery,
fp.quality.check, fp.racking.inspection, res.partner, sale.order
- XML view labels: action names, list/form/search strings,
portal template names, dashboard tile titles
What's deliberately preserved:
- DB model name 'fp.job' (technical identifier — used by
sale_order.x_fc_plating_job_ids and all comodel refs)
- Module name 'fusion_plating_jobs' (directory / import path)
- Settings -> Apps display label 'Fusion Plating Jobs' (module
identity for Odoo's app picker)
- 'Use Native Plating Jobs' migration toggle (internal mechanism
flag, not user-facing terminology)
Verified on entech: WH/JOB/01368 now displays as 'WO # 01368'
everywhere humans look (form header, breadcrumbs, M2O dropdowns,
error messages, smart-button titles).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
105 lines
3.7 KiB
Python
105 lines
3.7 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.
|
||
#
|
||
# Phase 1 (Sub 11) — relocated from fusion_plating_bridge_mrp.
|
||
# MRP-flavoured fields (production_id, workorder_id) replaced by their
|
||
# native fp.job / fp.job.step equivalents.
|
||
|
||
from odoo import api, fields, models, _
|
||
|
||
|
||
class FpJobConsumption(models.Model):
|
||
"""A single consumable drawdown charged to a plating job.
|
||
|
||
Sources include bath replenishment applied against a job, masking tape
|
||
rolls, PPE, nickel salts — anything that has a cost and should roll
|
||
into job costing.
|
||
|
||
Kept deliberately lightweight: one row per event, cost derived from
|
||
`product.standard_price` at log time (snapshot, not reactive).
|
||
"""
|
||
_name = 'fp.job.consumption'
|
||
_description = 'Fusion Plating — Job Consumption'
|
||
_order = 'logged_date desc, id desc'
|
||
|
||
job_id = fields.Many2one(
|
||
'fp.job', string='Work Order',
|
||
required=True, ondelete='cascade', index=True,
|
||
)
|
||
step_id = fields.Many2one(
|
||
'fp.job.step', string='Job Step',
|
||
domain="[('job_id', '=', job_id)]",
|
||
ondelete='set null',
|
||
)
|
||
product_id = fields.Many2one(
|
||
'product.product', string='Product', required=True,
|
||
domain="[('sale_ok', '=', False)]",
|
||
)
|
||
product_name = fields.Char(
|
||
string='Product Name (snapshot)',
|
||
help='Free-text product label if no inventory product is linked.',
|
||
)
|
||
quantity = fields.Float(string='Quantity', required=True, digits=(12, 3))
|
||
uom_id = fields.Many2one(
|
||
'uom.uom', string='UoM',
|
||
)
|
||
currency_id = fields.Many2one(
|
||
'res.currency', required=True,
|
||
default=lambda self: self.env.company.currency_id,
|
||
)
|
||
unit_cost = fields.Monetary(
|
||
string='Unit Cost (snapshot)', currency_field='currency_id',
|
||
help='Taken from product.standard_price at log time.',
|
||
)
|
||
total_cost = fields.Monetary(
|
||
string='Total Cost', currency_field='currency_id',
|
||
compute='_compute_total_cost', store=True,
|
||
)
|
||
logged_date = fields.Datetime(
|
||
string='Logged', default=fields.Datetime.now,
|
||
)
|
||
logged_by_id = fields.Many2one(
|
||
'res.users', string='Logged By', default=lambda self: self.env.user,
|
||
)
|
||
source = fields.Selection(
|
||
[('replenishment', 'Bath Replenishment'),
|
||
('masking', 'Masking Material'),
|
||
('ppe', 'PPE / Consumables'),
|
||
('chemistry', 'Process Chemistry'),
|
||
('other', 'Other')],
|
||
string='Source', default='other', required=True,
|
||
)
|
||
replenishment_id = fields.Many2one(
|
||
'fusion.plating.bath.replenishment.suggestion',
|
||
string='Replenishment Suggestion',
|
||
ondelete='set null',
|
||
)
|
||
notes = fields.Char(string='Notes')
|
||
|
||
@api.depends('quantity', 'unit_cost')
|
||
def _compute_total_cost(self):
|
||
for rec in self:
|
||
rec.total_cost = round((rec.quantity or 0) * (rec.unit_cost or 0), 2)
|
||
|
||
@api.depends('product_id', 'product_name', 'quantity', 'job_id')
|
||
def _compute_display_name(self):
|
||
for rec in self:
|
||
label = rec.product_id.display_name or rec.product_name or 'Consumption'
|
||
qty = ('%g' % rec.quantity) if rec.quantity else ''
|
||
job = rec.job_id.name or ''
|
||
bits = [label]
|
||
if qty:
|
||
bits.append('×' + qty)
|
||
if job:
|
||
bits.append('(%s)' % job)
|
||
rec.display_name = ' '.join(bits)
|
||
|
||
@api.onchange('product_id')
|
||
def _onchange_product(self):
|
||
if self.product_id:
|
||
self.product_name = self.product_id.display_name
|
||
self.unit_cost = self.product_id.standard_price or 0.0
|
||
self.uom_id = self.product_id.uom_id or False
|