diff --git a/fusion_plating/fusion_plating/__manifest__.py b/fusion_plating/fusion_plating/__manifest__.py index 47f58352..aaa933b4 100644 --- a/fusion_plating/fusion_plating/__manifest__.py +++ b/fusion_plating/fusion_plating/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating', - 'version': '19.0.5.1.0', + 'version': '19.0.5.2.0', 'category': 'Manufacturing/Plating', 'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.', 'description': """ diff --git a/fusion_plating/fusion_plating/models/res_company.py b/fusion_plating/fusion_plating/models/res_company.py index e61495f0..aa1733c6 100644 --- a/fusion_plating/fusion_plating/models/res_company.py +++ b/fusion_plating/fusion_plating/models/res_company.py @@ -59,6 +59,70 @@ class ResCompany(models.Model): help='Facility used when the context does not specify one (single-site shops).', ) + # ----- Unit-of-measure defaults -------------------------------------- + # Plating shops in different jurisdictions / industries use different + # measurement systems. North-American aerospace shops live in °F + mils; + # ROW + most industrial shops use °C + microns. Each company picks its + # defaults once here; every WO / oven / bath log / thickness reading + # inherits the choice. Per-record overrides remain possible. + x_fc_default_temp_uom = fields.Selection( + [('F', '°F (Fahrenheit)'), + ('C', '°C (Celsius)')], + string='Temperature Unit', + default='F', + help='Used for bake temps, oven setpoints, bath temperatures.', + ) + x_fc_default_thickness_uom = fields.Selection( + [('mils', 'mils'), + ('microns', 'µm (microns)'), + ('inches', 'inches'), + ('mm', 'mm')], + string='Thickness Unit', + default='mils', + help='Used for coating spec targets and Fischerscope readings.', + ) + x_fc_default_volume_uom = fields.Selection( + [('gal', 'US Gallons'), + ('L', 'Litres'), + ('imp_gal', 'Imperial Gallons')], + string='Volume Unit', + default='gal', + help='Used for bath volumes and chemical addition logs.', + ) + x_fc_default_mass_uom = fields.Selection( + [('lb', 'Pounds (lb)'), + ('kg', 'Kilograms (kg)'), + ('oz', 'Ounces (oz)'), + ('g', 'Grams (g)')], + string='Mass Unit', + default='lb', + help='Used for chemical doses, parts weight, waste manifests.', + ) + x_fc_default_pressure_uom = fields.Selection( + [('psi', 'PSI'), + ('bar', 'bar'), + ('kPa', 'kPa')], + string='Pressure Unit', + default='psi', + help='Used for compressed-air pressure, agitation, etc.', + ) + x_fc_default_current_density_uom = fields.Selection( + [('asf', 'A/ft² (ASF)'), + ('asd', 'A/dm² (ASD)')], + string='Current Density Unit', + default='asf', + help='Used for electrolytic plating bath current density.', + ) + x_fc_default_area_uom = fields.Selection( + [('sq_in', 'sq in'), + ('sq_ft', 'sq ft'), + ('sq_cm', 'cm²'), + ('sq_m', 'm²')], + string='Area Unit', + default='sq_in', + help='Used for part surface area, masking area.', + ) + def _compute_x_fc_facility_count(self): for rec in self: rec.x_fc_facility_count = len(rec.x_fc_facility_ids) diff --git a/fusion_plating/fusion_plating/models/res_config_settings.py b/fusion_plating/fusion_plating/models/res_config_settings.py index c9a7b665..fcc62866 100644 --- a/fusion_plating/fusion_plating/models/res_config_settings.py +++ b/fusion_plating/fusion_plating/models/res_config_settings.py @@ -25,3 +25,33 @@ class ResConfigSettings(models.TransientModel): readonly=False, string='Default Mastery Threshold', ) + + # ----- Unit-of-measure defaults -------------------------------------- + x_fc_default_temp_uom = fields.Selection( + related='company_id.x_fc_default_temp_uom', + readonly=False, string='Temperature Unit', + ) + x_fc_default_thickness_uom = fields.Selection( + related='company_id.x_fc_default_thickness_uom', + readonly=False, string='Thickness Unit', + ) + x_fc_default_volume_uom = fields.Selection( + related='company_id.x_fc_default_volume_uom', + readonly=False, string='Volume Unit', + ) + x_fc_default_mass_uom = fields.Selection( + related='company_id.x_fc_default_mass_uom', + readonly=False, string='Mass Unit', + ) + x_fc_default_pressure_uom = fields.Selection( + related='company_id.x_fc_default_pressure_uom', + readonly=False, string='Pressure Unit', + ) + x_fc_default_current_density_uom = fields.Selection( + related='company_id.x_fc_default_current_density_uom', + readonly=False, string='Current Density Unit', + ) + x_fc_default_area_uom = fields.Selection( + related='company_id.x_fc_default_area_uom', + readonly=False, string='Area Unit', + ) diff --git a/fusion_plating/fusion_plating/views/res_config_settings_views.xml b/fusion_plating/fusion_plating/views/res_config_settings_views.xml index 0dc6df66..62bea3e5 100644 --- a/fusion_plating/fusion_plating/views/res_config_settings_views.xml +++ b/fusion_plating/fusion_plating/views/res_config_settings_views.xml @@ -37,6 +37,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fusion_plating/fusion_plating_bridge_mrp/__manifest__.py b/fusion_plating/fusion_plating_bridge_mrp/__manifest__.py index ab820314..8fea443c 100644 --- a/fusion_plating/fusion_plating_bridge_mrp/__manifest__.py +++ b/fusion_plating/fusion_plating_bridge_mrp/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Fusion Plating — MRP Bridge", - 'version': '19.0.6.7.0', + 'version': '19.0.6.8.0', 'category': 'Manufacturing/Plating', 'summary': 'Bridge Fusion Plating facilities, baths and tanks to Odoo MRP work orders.', 'description': """ diff --git a/fusion_plating/fusion_plating_bridge_mrp/models/mrp_workorder.py b/fusion_plating/fusion_plating_bridge_mrp/models/mrp_workorder.py index 752cb34d..4941848b 100644 --- a/fusion_plating/fusion_plating_bridge_mrp/models/mrp_workorder.py +++ b/fusion_plating/fusion_plating_bridge_mrp/models/mrp_workorder.py @@ -71,8 +71,15 @@ class MrpWorkorder(models.Model): 'which one for the chart-recorder trail.', ) x_fc_bake_temp = fields.Float( - string='Bake Temp (°F)', digits=(5, 1), - help='Setpoint temperature recorded for this bake WO.', + string='Bake Temp', digits=(5, 1), + help='Setpoint temperature recorded for this bake WO. Unit ' + 'follows the company default (Settings → Fusion Plating → ' + 'Units of Measure) — overrideable per WO via Temp Unit.', + ) + x_fc_bake_temp_uom = fields.Selection( + [('F', '°F'), ('C', '°C')], + string='Temp Unit', + default=lambda self: self.env.company.x_fc_default_temp_uom or 'F', ) x_fc_bake_duration_hours = fields.Float( string='Bake Duration (h)', digits=(5, 2), @@ -811,7 +818,8 @@ class MrpWorkorder(models.Model): continue missing = [] if not wo.x_fc_bake_temp: - missing.append(_('Bake Temp (°F)')) + unit = '°' + (wo.x_fc_bake_temp_uom or 'F') + missing.append(_('Bake Temp (%s)') % unit) if not wo.x_fc_bake_duration_hours: missing.append(_('Bake Duration (h)')) if wo.x_fc_oven_id and not wo.x_fc_oven_id.chart_recorder_ref: diff --git a/fusion_plating/fusion_plating_bridge_mrp/views/mrp_workorder_views.xml b/fusion_plating/fusion_plating_bridge_mrp/views/mrp_workorder_views.xml index 4a2971bd..53a891df 100644 --- a/fusion_plating/fusion_plating_bridge_mrp/views/mrp_workorder_views.xml +++ b/fusion_plating/fusion_plating_bridge_mrp/views/mrp_workorder_views.xml @@ -199,7 +199,12 @@ required="x_fc_requires_oven"/> - + diff --git a/fusion_plating/scripts/fp_uom_smoke.py b/fusion_plating/scripts/fp_uom_smoke.py new file mode 100644 index 00000000..6a2b7827 --- /dev/null +++ b/fusion_plating/scripts/fp_uom_smoke.py @@ -0,0 +1,35 @@ +env = env # noqa +co = env.company +print('Company unit defaults on', co.name) +for f in ('x_fc_default_temp_uom', 'x_fc_default_thickness_uom', + 'x_fc_default_volume_uom', 'x_fc_default_mass_uom', + 'x_fc_default_pressure_uom', 'x_fc_default_current_density_uom', + 'x_fc_default_area_uom'): + print(f' {f:<36} {getattr(co, f, "(missing)")}') + +# Switch company default to Celsius and verify a new WO inherits it +print('\\nSwitching company default to °C...') +co.sudo().x_fc_default_temp_uom = 'C' + +mo = env['mrp.production'].sudo().search([], order='id desc', limit=1) +if mo: + bake_wo = mo.workorder_ids.filtered( + lambda w: hasattr(w, '_fp_classify_kind') and w._fp_classify_kind() == 'bake' + )[:1] + if bake_wo: + # Existing WOs keep their stored value + print(f'existing bake WO {bake_wo.id}: x_fc_bake_temp_uom = {bake_wo.x_fc_bake_temp_uom}') + + # New WO should default from current company setting + new_wo_vals = { + 'production_id': mo.id, 'name': 'Test Bake WO', + 'workcenter_id': mo.workorder_ids[0].workcenter_id.id, + } + new_wo = env['mrp.workorder'].sudo().create(new_wo_vals) + print(f'NEW WO {new_wo.id}: x_fc_bake_temp_uom = {new_wo.x_fc_bake_temp_uom} (should be C)') + new_wo.sudo().unlink() + +# Restore F default +co.sudo().x_fc_default_temp_uom = 'F' +print('Restored to °F.') +env.cr.commit()