Files
Odoo-Modules/fusion_plating/fusion_plating/models/fp_job_step_move.py
gsinghpal 4187842d30 feat(sub12b): fp.job.step.move + fp.job.step.move.input.value
Chain-of-custody log: one row per Move Parts / Move Rack commit.
FP/MOVE/YYYY/NNNN sequence (5-digit). Carries from/to step + tank,
transfer type, qty, location, photo, rack, operator, datetime.

Child model captures recorded transition-input values (Sub 12a's
fp.step.template.transition.input snapshots → fp.job.step.move.
input.value rows). Each row carries 5 typed value columns; the
controller (Task 8) picks the right one based on input_type.

Operators get read+write+create — they generate moves at runtime —
but no unlink. Manager-only deletes for audit safety.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:04:41 -04:00

105 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from odoo import api, fields, models
class FpJobStepMove(models.Model):
"""Chain-of-custody log — one row per part-batch move.
Sub 12b: every Move Parts / Move Rack click commits one (or, for
rack moves, one-per-batch atomic) row here. Sub 12c walks these in
chronological order to render the customer CoC PDF.
"""
_name = 'fp.job.step.move'
_description = 'Fusion Plating — Job Step Move (Chain-of-Custody)'
_inherit = ['mail.thread']
_order = 'move_datetime desc, id desc'
name = fields.Char(
string='Move Reference',
default=lambda self: self.env['ir.sequence'].next_by_code(
'fp.job.step.move') or '/',
readonly=True, copy=False,
)
job_id = fields.Many2one('fp.job', string='Job',
required=True, ondelete='cascade', index=True)
from_step_id = fields.Many2one('fp.job.step', string='From Step',
ondelete='set null', index=True)
to_step_id = fields.Many2one('fp.job.step', string='To Step',
ondelete='set null', index=True, required=True)
from_tank_id = fields.Many2one('fusion.plating.tank',
related='from_step_id.tank_id', store=True)
to_tank_id = fields.Many2one('fusion.plating.tank', string='To Tank',
ondelete='set null')
transfer_type = fields.Selection([
('step', 'Step'),
('hold', 'Hold'),
('scrap', 'Scrap'),
('rework', 'Rework'),
('split', 'Split'),
('return', 'Return'),
], string='Transfer Type', default='step', required=True)
qty_moved = fields.Integer(string='Qty Moved', required=True)
qty_available_at_move = fields.Integer(string='Qty Available')
to_location = fields.Selection([
('global', 'Global'),
('quarantine', 'Quarantine'),
('staging_a', 'Staging A'),
('staging_b', 'Staging B'),
('shipping_dock', 'Shipping Dock'),
('scrap_bin', 'Scrap Bin'),
], string='To Location', default='global')
photo_evidence_id = fields.Many2one('ir.attachment',
string='Photo Evidence', ondelete='set null')
customer_wo_count = fields.Integer(string='# Customer WOs')
rack_id = fields.Many2one('fusion.plating.rack',
string='Rack', ondelete='set null', index=True)
unrack_after_move = fields.Boolean(string='Unrack After Move')
moved_by_user_id = fields.Many2one('res.users', string='Moved By',
default=lambda self: self.env.user, required=True)
move_datetime = fields.Datetime(string='Move Time',
default=fields.Datetime.now, required=True, index=True)
transition_input_value_ids = fields.One2many(
'fp.job.step.move.input.value', 'move_id',
string='Transition Input Values',
)
class FpJobStepMoveInputValue(models.Model):
"""Captured value for one transition-input prompt.
Each row = one author-defined prompt × one move. Snapshot of what
the operator typed at move-time. Used by Sub 12c CoC report.
"""
_name = 'fp.job.step.move.input.value'
_description = 'Fusion Plating — Captured Transition Input Value'
_order = 'move_id, id'
move_id = fields.Many2one('fp.job.step.move', string='Move',
required=True, ondelete='cascade', index=True)
template_input_id = fields.Many2one(
'fp.step.template.transition.input',
string='Template Input', ondelete='set null',
help='What was originally asked (template-level reference).')
node_input_id = fields.Many2one(
'fusion.plating.process.node.input',
string='Node Input', ondelete='set null',
help='Snapshot of the authored prompt at job-creation time.')
value_text = fields.Char(string='Text Value')
value_number = fields.Float(string='Number Value')
value_boolean = fields.Boolean(string='Yes/No Value')
value_date = fields.Datetime(string='Date Value')
value_attachment_id = fields.Many2one('ir.attachment',
string='Attachment Value', ondelete='set null')