diff --git a/fusion_plating/fusion_plating/__manifest__.py b/fusion_plating/fusion_plating/__manifest__.py index 697d2988..dd796dcc 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.18.12.0', + 'version': '19.0.18.12.1', 'category': 'Manufacturing/Plating', 'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.', 'description': """ diff --git a/fusion_plating/fusion_plating/controllers/recipe_controller.py b/fusion_plating/fusion_plating/controllers/recipe_controller.py index a3f988b6..b69f6a56 100644 --- a/fusion_plating/fusion_plating/controllers/recipe_controller.py +++ b/fusion_plating/fusion_plating/controllers/recipe_controller.py @@ -53,7 +53,7 @@ class FpRecipeController(http.Controller): 'name': name, 'node_type': node_type, 'parent_id': parent.id, - 'sequence': max_seq + 10, + 'sequence': max_seq + 1, } if vals: data.update(vals) @@ -132,7 +132,7 @@ class FpRecipeController(http.Controller): Node = request.env['fusion.plating.process.node'] try: for idx, nid in enumerate(node_ids): - Node.browse(int(nid)).write({'sequence': (idx + 1) * 10}) + Node.browse(int(nid)).write({'sequence': idx + 1}) return {'ok': True} except Exception as exc: _logger.exception('Recipe reorder failed') @@ -195,7 +195,7 @@ class FpRecipeController(http.Controller): if a_seq == b_seq: # Sequences collided — renumber everyone cleanly, then swap for i, s in enumerate(siblings, 1): - s.sequence = i * 10 + s.sequence = i a_seq, b_seq = node.sequence, other.sequence node.sequence, other.sequence = b_seq, a_seq return {'ok': True} @@ -260,7 +260,7 @@ class FpRecipeController(http.Controller): vals['sequence'] = base_seq new_node = Node.create(vals) for i, child in enumerate(src_node.child_ids.sorted('sequence'), 1): - _copy_subtree(child, new_node, i * 10) + _copy_subtree(child, new_node, i) return new_node # Phase 1 — create every copied top-level child, tracking their @@ -308,8 +308,8 @@ class FpRecipeController(http.Controller): + existing_top[anchor_idx:] ) for i, node in enumerate(final_order, 1): - if node.sequence != i * 10: - node.sequence = i * 10 + if node.sequence != i: + node.sequence = i return { 'ok': True, @@ -341,7 +341,7 @@ class FpRecipeController(http.Controller): max_seq = max((c.sequence for c in parent.child_ids), default=0) node.write({ 'parent_id': parent.id, - 'sequence': max_seq + 10, + 'sequence': max_seq + 1, }) return {'ok': True} except Exception as exc: diff --git a/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py b/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py index f6c3f1b6..de11edb2 100644 --- a/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py +++ b/fusion_plating/fusion_plating/controllers/simple_recipe_controller.py @@ -271,7 +271,7 @@ class SimpleRecipeController(http.Controller): 'template_id': tpl.id, 'name': (payload or {}).get('name') or 'New Prompt', 'input_type': (payload or {}).get('input_type') or 'text', - 'sequence': existing_max + 10, + 'sequence': existing_max + 1, 'required': bool((payload or {}).get('required')), }) return {'ok': True, 'input_id': rec.id, @@ -356,25 +356,26 @@ class SimpleRecipeController(http.Controller): return {'id': new_node.id, 'sequence': new_node.sequence} def _sequence_for_position(self, recipe, position): + """Return the sequence value for a NEW step inserted at + `position` among the recipe's existing children. + + Always renumbers existing siblings so the result is contiguous + 1, 2, 3, ... matching what the operator sees on the work order. + (Pre-Sub 13c we used 10-spacing to allow midpoint inserts — + operators kept asking why their first step said "Step 10".) + """ siblings = recipe.child_ids.sorted('sequence') if not siblings: - return 10 - if position >= len(siblings): - return siblings[-1].sequence + 10 - if position <= 0: - return max(1, siblings[0].sequence - 10) - before = siblings[position - 1].sequence - after = siblings[position].sequence - if after - before > 1: - return (before + after) // 2 - # Sequences are tightly packed (gap == 1 → midpoint == after, - # which collides). Renumber siblings to 10/20/30… first, then - # the new step lands cleanly between renumbered neighbours. + return 1 + pos = max(0, min(position, len(siblings))) + # Make room: siblings before `pos` keep their 1-based index; + # siblings at or after `pos` shift up by one so the new step + # lands at sequence (pos + 1). for idx, sib in enumerate(siblings): - new_seq = (idx + 1) * 10 - if sib.sequence != new_seq: - sib.sequence = new_seq - return position * 10 + 5 + target = idx + 1 if idx < pos else idx + 2 + if sib.sequence != target: + sib.sequence = target + return pos + 1 def _copy_inputs_from_template(self, tpl, new_node): NodeInput = request.env['fusion.plating.process.node.input'] @@ -412,7 +413,7 @@ class SimpleRecipeController(http.Controller): def step_reorder(self, node_ids): Node = request.env['fusion.plating.process.node'] for i, nid in enumerate(node_ids, start=1): - Node.browse(nid).write({'sequence': i * 10}) + Node.browse(nid).write({'sequence': i}) return {'ok': True} # -------------------------------------------------------------- template @@ -521,7 +522,7 @@ class SimpleRecipeController(http.Controller): 'input_type': (payload or {}).get('input_type') or 'text', 'kind': 'step_input', 'collect': True, - 'sequence': existing_max + 10, + 'sequence': existing_max + 1, 'required': bool((payload or {}).get('required')), }) return {'ok': True, 'input_id': rec.id} diff --git a/fusion_plating/fusion_plating_bridge_mrp/__manifest__.py b/fusion_plating/fusion_plating_bridge_mrp/__manifest__.py index 8be6e557..cd82356a 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.13.0.0', + 'version': '19.0.13.0.1', '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_production.py b/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py index adfb9d66..7416d3b3 100644 --- a/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py +++ b/fusion_plating/fusion_plating_bridge_mrp/models/mrp_production.py @@ -572,7 +572,7 @@ class MrpProduction(models.Model): # Walk tree and collect operation WO values wo_vals_list = [] wo_steps = {} # {sequence: instruction text} — posted to WO chatter after create - seq_counter = [10] # mutable for closure, increments by 10 + seq_counter = [1] # mutable for closure, increments by 1 def _is_node_included(node): """Determine if a node should be included based on opt-in/out @@ -695,7 +695,7 @@ class MrpProduction(models.Model): wo_vals_list.append(vals) if steps: wo_steps[seq_counter[0]] = '\n'.join(steps) - seq_counter[0] += 10 + seq_counter[0] += 1 elif node.node_type in ('recipe', 'sub_process'): # Container nodes — recurse into children diff --git a/fusion_plating/fusion_plating_jobs/__manifest__.py b/fusion_plating/fusion_plating_jobs/__manifest__.py index 39c16d6e..8144a01e 100644 --- a/fusion_plating/fusion_plating_jobs/__manifest__.py +++ b/fusion_plating/fusion_plating_jobs/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Plating — Native Jobs', - 'version': '19.0.8.17.3', + 'version': '19.0.8.17.4', 'category': 'Manufacturing/Plating', 'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.', 'author': 'Nexa Systems Inc.', diff --git a/fusion_plating/fusion_plating_jobs/models/fp_job.py b/fusion_plating/fusion_plating_jobs/models/fp_job.py index 3e72606a..61d56041 100644 --- a/fusion_plating/fusion_plating_jobs/models/fp_job.py +++ b/fusion_plating/fusion_plating_jobs/models/fp_job.py @@ -606,7 +606,12 @@ class FpJob(models.Model): step_vals_list = [] wo_steps = {} # {sequence: instruction text} - seq_counter = [10] + # Sequences increment by 1 (operator-friendly: Step 1, 2, 3, + # ...) instead of the legacy 10/20/30 spacing. The 10-spacing + # was originally there to allow midpoint inserts, but + # operators kept asking why their work order said "Step 10" + # for the first row. + seq_counter = [1] def _is_node_included(node): """Determine if a node should be included based on @@ -759,7 +764,7 @@ class FpJob(models.Model): step_vals_list.append(vals) if instructions: wo_steps[seq_counter[0]] = '\n'.join(instructions) - seq_counter[0] += 10 + seq_counter[0] += 1 elif node.node_type in ('recipe', 'sub_process'): for child in node.child_ids.sorted('sequence'):