mrp_packaging_qty/models/mrp_production.py

130 lines
5.8 KiB
Python

from odoo import api, fields, models
class MrpProduction(models.Model):
_inherit = 'mrp.production'
packaging_id = fields.Many2one('mrp.packaging', string='Packaging', domain="[('product_tmpl_id', '=', product_tmpl_id)]", check_company=True)
packaging_qty = fields.Float('Quantity Packaging', default=0.0)
@api.onchange('packaging_qty')
def _onchange_packaging_qty(self):
if self.packaging_id and self.packaging_qty:
self.product_qty = self.packaging_id.qty * self.packaging_qty
@api.onchange('packaging_id')
def _onchange_packaging_id(self):
if self.packaging_id and self.packaging_id.qty:
self.packaging_qty = self.product_qty / self.packaging_id.qty
else:
self.packaging_qty = 0.0
qty_producing_packaging = fields.Float('Quantity Producing Packaging', compute='_compute_qty_producing_packaging', inverse='_inverse_qty_producing_packaging', digits=(16, 2))
@api.depends('qty_producing', 'packaging_id', 'packaging_id.qty')
def _compute_qty_producing_packaging(self):
for record in self:
if record.packaging_id and record.packaging_id.qty:
record.qty_producing_packaging = record.qty_producing / record.packaging_id.qty
else:
record.qty_producing_packaging = 0.0
def _inverse_qty_producing_packaging(self):
for record in self:
if record.packaging_id and record.packaging_id.qty:
record.qty_producing = record.qty_producing_packaging * record.packaging_id.qty
record._merge_finished_move_lines()
@api.onchange('qty_producing_packaging')
def _onchange_qty_producing_packaging(self):
if self.packaging_id and self.packaging_id.qty:
self.qty_producing = self.qty_producing_packaging * self.packaging_id.qty
self._onchange_qty_producing()
self._merge_finished_move_lines()
@api.onchange('qty_producing')
def _onchange_qty_producing(self):
super()._onchange_qty_producing()
self._merge_finished_move_lines()
def write(self, vals):
res = super().write(vals)
if 'qty_producing' in vals or 'qty_producing_packaging' in vals:
self._merge_finished_move_lines()
return res
def _set_qty_producing(self, *args, **kwargs):
res = super()._set_qty_producing(*args, **kwargs)
self._merge_finished_move_lines()
return res
def _post_inventory(self, *args, **kwargs):
res = super()._post_inventory(*args, **kwargs)
self._merge_finished_move_lines()
return res
def _merge_finished_move_lines(self):
for production in self:
# Process ALL finished moves, even DONE ones, to catch splits that happened during validation
moves = production.move_finished_ids.filtered(lambda m: m.product_id == production.product_id and m.state != 'cancel')
for move in moves:
# print(f"DEBUG MERGE: Processing move {move.id}, lines found: {len(move.move_line_ids)}")
lines_by_key = {}
# track lines to unlink or zero-out (if done)
# Keep the original line (smallest ID) to preserve consistency
sorted_lines = move.move_line_ids.sorted('id')
for line in sorted_lines:
# Use IDs for the key to ensure reliable grouping
# Include lot_name in case lot_id is not yet set
key = (
line.lot_id.id,
line.lot_name,
line.location_id.id,
line.location_dest_id.id,
line.package_id.id,
line.result_package_id.id,
line.owner_id.id,
line.product_id.id
)
if key in lines_by_key:
target_line = lines_by_key[key]
# print(f"DEBUG MERGE: Merging line {line.id} into {target_line.id}")
# Merge Quantities
target_line.quantity += line.quantity
# Preserve Traceability Links
if line.consume_line_ids:
target_line.consume_line_ids |= line.consume_line_ids
if line.produce_line_ids:
target_line.produce_line_ids |= line.produce_line_ids
# If the line is DONE, we cannot unlink it via ORM.
# But the user wants it gone from the report (0 qty is not enough).
# So we use SQL Delete (Hard Delete).
if line.state == 'done':
# print(f"DEBUG MERGE: SQL Deleting DONE line {line.id}")
self.env.cr.execute("DELETE FROM stock_move_line WHERE id = %s", (line.id,))
line.invalidate_recordset()
else:
# print(f"DEBUG MERGE: Unlinking line {line.id}")
line.unlink()
else:
lines_by_key[key] = line
@api.onchange('product_qty')
def _onchange_product_qty(self):
if self.packaging_id and self.packaging_id.qty:
self.packaging_qty = self.product_qty / self.packaging_id.qty
@api.onchange('bom_id')
def _onchange_bom_id(self):
super()._onchange_bom_id()
if self.bom_id and self.bom_id.packaging_id:
self.packaging_id = self.bom_id.packaging_id
self.packaging_qty = self.bom_id.packaging_qty
# Trigger qty calculation
self._onchange_packaging_qty()