From 1d04ac8cb72a262e7b56221b4a8bfc43aae7daf0 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Fri, 22 May 2026 21:43:36 -0400 Subject: [PATCH] feat(fusion_plating_jobs): fp.job.display_wo_name compute (WO # 00001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plan task P1.1. Formats fp.job.name as "WO # " for tablet/dashboard surfaces. Underlying name field is unchanged so back-office forms, reports, and emails keep WH/JOB/00001. Tests not run locally — fusion_plating not mounted in odoo-modsdev container. Verify on entech: -u fusion_plating_jobs --test-tags fp_jobs. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../fusion_plating_jobs/models/fp_job.py | 24 ++++++++++++ .../tests/test_display_wo_name.py | 38 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 fusion_plating/fusion_plating_jobs/tests/test_display_wo_name.py diff --git a/fusion_plating/fusion_plating_jobs/models/fp_job.py b/fusion_plating/fusion_plating_jobs/models/fp_job.py index 88d732e9..9810a39b 100644 --- a/fusion_plating/fusion_plating_jobs/models/fp_job.py +++ b/fusion_plating/fusion_plating_jobs/models/fp_job.py @@ -97,6 +97,30 @@ class FpJob(models.Model): 'idempotency. Cleared post-cutover.', ) + # Display formatter — "WO # 00001" used everywhere on tablet/dashboard. + # The underlying `name` field stays untouched (WH/JOB/00001) so reports, + # emails, and back-office forms continue using their canonical name. + # System-wide sequence rename is a separate decision (see spec + # 2026-05-22-shopfloor-tablet-redesign-design §6.5). + display_wo_name = fields.Char( + compute='_compute_display_wo_name', + string='WO #', + help='Tablet/dashboard formatter — "WO # 00001" derived from name. ' + 'Underlying name field is unchanged.', + ) + + @api.depends('name') + def _compute_display_wo_name(self): + for job in self: + raw = (job.name or '').strip() + if not raw: + job.display_wo_name = '' + continue + # Take the last "/"-separated segment as the number portion. + # WH/JOB/00001 → 00001 ; WH/JOB/2026/00042 → 00042 ; 00123 → 00123 + tail = raw.rsplit('/', 1)[-1] + job.display_wo_name = f'WO # {tail}' + # ------------------------------------------------------------------ # Sub 14 — Configurable workflow state (status bar milestone) # ------------------------------------------------------------------ diff --git a/fusion_plating/fusion_plating_jobs/tests/test_display_wo_name.py b/fusion_plating/fusion_plating_jobs/tests/test_display_wo_name.py new file mode 100644 index 00000000..dd0bd020 --- /dev/null +++ b/fusion_plating/fusion_plating_jobs/tests/test_display_wo_name.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. — License OPL-1 +from odoo.tests.common import TransactionCase, tagged + + +@tagged('-at_install', 'post_install', 'fp_jobs') +class TestDisplayWoName(TransactionCase): + """fp.job.display_wo_name — Tablet/dashboard formatter.""" + + def setUp(self): + super().setUp() + self.partner = self.env['res.partner'].create({'name': 'Test Cust'}) + self.product = self.env['product.product'].create({'name': 'Test Prod'}) + + def _make_job(self, name): + return self.env['fp.job'].create({ + 'name': name, + 'partner_id': self.partner.id, + 'product_id': self.product.id, + 'qty': 1, + }) + + def test_wh_job_prefix_formatted(self): + job = self._make_job('WH/JOB/00001') + self.assertEqual(job.display_wo_name, 'WO # 00001') + + def test_wh_job_with_year(self): + job = self._make_job('WH/JOB/2026/00042') + self.assertEqual(job.display_wo_name, 'WO # 00042') + + def test_plain_numeric(self): + job = self._make_job('00123') + self.assertEqual(job.display_wo_name, 'WO # 00123') + + def test_falsy_name(self): + # New record before save → name is False; computed returns empty + job = self.env['fp.job'].new({'name': False}) + self.assertEqual(job.display_wo_name, '')