stock-logistics-reporting icon indicating copy to clipboard operation
stock-logistics-reporting copied to clipboard

[16.0] stock_picking_report_valued_sale_mrp: kit component demanded quantity is doubled when a delivery is fully returned and then redelivered

Open rrebollo opened this issue 1 month ago • 1 comments

Module

stock_picking_report_valued_sale_mrp – Odoo 16.0

Description

When a kit (phantom BOM) is delivered, fully returned, and then redelivered, the valued delivery reports Delivery Slip show twice the correct quantity and value for kit components.

The root cause is the method _get_components_per_kit() in models/stock_move.py, which incorrectly computes the demanded component quantity from the sale line when returns and redeliveries are present.

Current (wrong) behaviour

The method returns 80 components per kit instead of the correct 40 components per kit

Expected behaviour

A sale line demanding 2 kits must always show 40 components per kit in the report (80 units delivered / 2 kits ordered = 40), regardless of how many times the delivery was returned and redelivered).
Net effect: customer finally received 2 kits → component consumption must be valued for 2 kits only.

Real data example (anonymized but 100% representative)

id name product_id product_qty product_uom_qty move_dest_ids move_orig_ids picking_id state origin_returned_move_id returned_move_ids quantity_done picking_code sale_line_id
MV-01 [BOX-01] PRD-01 80 80 MV-02 PK-01, ALB/XXXX PK-10 done false MV-02 80 outgoing SO-2501524
MV-02 [BOX-01] PRD-01 80 80 MV-01 PK-02, RET/XXXX PK-11 done MV-01 (SO-2501524: Stock>Customers) (none) 80 incoming SO-2501524
MV-03 [BOX-01] PRD-01 80 80 PK-03, ALB/XXXX (none) PK-12 done false (none) 80 outgoing SO-2501524

Why the current code fails

Current implementation (lines 9–31):

component_demand = sum(
    sale_line.move_ids.filtered(
        lambda x: x.product_id == self.product_id
        and not x.origin_returned_move_id   # excludes only return moves
        and ...
    ).mapped("product_uom_qty")
)

Result with the data above:

MV-01 → included (80)
MV-02 → correctly excluded (return)
MV-03 → included (80)

→ total = 160 → 160 / 2 kits ordered = 80 components per kit (doubled)
The original delivery quantity is never reduced by the quantity that was later returned, producing systematic over-valuation every time a return + replacement occurs.

### Buggy code (current)
https://github.com/OCA/stock-logistics-reporting/blob/56f7fc922cc9b4efd1100f6a51744871c1201704/stock_picking_report_valued_sale_mrp/models/stock_move.py#L9-L31

rrebollo avatar Nov 19 '25 05:11 rrebollo

@pedrobaeza @chienandalu Hi! I’d be glad to submit a fix PR if you can give me a quick pointer. First: with the three stock moves in the example (original delivery → full return → replacement delivery, all linked to the same sale line), is this chain considered normal in Odoo 16, or is the data somehow corrupted/unexpected? Thanks!

rrebollo avatar Nov 19 '25 05:11 rrebollo