addons-cm/stock_picking_batch_collect/models/stock_move_line.py
GitHub Copilot 18cfd38347
Some checks failed
CI / lint (pull_request) Successful in 32s
CI / test (pull_request) Failing after 3m15s
CI / review (pull_request) Has been skipped
[IMP] stock_picking_batch_collect: demanded quantity on the move line lists
The move lists already show the demand, the move line ones do not: the
detailed operations of the batch and of the transfer, and the operator
(Basket Assembly) view. Adds a read-only column with the demand of the
line's move, in the unit of the line, next to the ordered quantity.

Closes #21

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:34:56 +02:00

86 lines
2.8 KiB
Python

# Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api
from odoo import fields
from odoo import models
class StockMoveLine(models.Model):
_inherit = "stock.move.line"
_order = "product_categ_id, product_id, picking_partner_id, id"
product_categ_id = fields.Many2one(
comodel_name="product.category",
string="Product Category (Batch)",
related="product_id.categ_id",
store=True,
readonly=True,
)
product_default_code = fields.Char(
string="Product Code",
related="product_id.default_code",
readonly=True,
)
picking_partner_id = fields.Many2one(
related="picking_id.partner_id",
store=True,
readonly=True,
)
is_collected = fields.Boolean(
string="Collected",
default=False,
copy=False,
)
sale_ordered_qty = fields.Float(
string="Ordered Quantity",
digits="Product Unit of Measure",
compute="_compute_sale_ordered_qty",
)
move_demand_qty = fields.Float(
string="Demanded Quantity",
digits="Product Unit of Measure",
compute="_compute_move_demand_qty",
)
@api.depends("move_id.sale_ordered_qty", "move_id.product_uom", "product_uom_id")
def _compute_sale_ordered_qty(self):
for line in self:
move = line.move_id
if move.sale_ordered_qty and line.product_uom_id:
line.sale_ordered_qty = move.product_uom._compute_quantity(
move.sale_ordered_qty, line.product_uom_id, round=False
)
else:
line.sale_ordered_qty = 0.0
@api.depends("move_id.product_uom_qty", "move_id.product_uom", "product_uom_id")
def _compute_move_demand_qty(self):
"""The demand of the whole move: every line of a split move shows it."""
for line in self:
move = line.move_id
if move.product_uom and line.product_uom_id:
line.move_demand_qty = move.product_uom._compute_quantity(
move.product_uom_qty, line.product_uom_id, round=False
)
else:
line.move_demand_qty = 0.0
def write(self, vals):
res = super().write(vals)
if vals.get("is_collected"):
# Collecting a line is the operator saying the goods are in the
# basket: its quantity must survive the reservation engine even if
# it was never retyped. The demand is left alone, only a quantity
# typed by hand adjusts it.
lines = self.filtered(
lambda line: not line.picked and line.state not in ("done", "cancel")
)
if lines:
lines.picked = True
lines._freeze_manual_quantity(align_demand=False)
return res