From acbeb9b3c66618acae33afe296a609ac76619dca Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Tue, 11 Jan 2022 10:11:00 +0000 Subject: [PATCH] [FIX] sale_stock: display lots on invoices When printing an invoice with tracked products, if there are several invoices linked to the sale order, the displayed lots may be incorrect To reproduce the issue: (Need sale_management) 1. In Settings, enable "Display Lots & Serial Numbers on Invoices" 2. Create two products P01, P02: - Storable - Tracked by lot 3. Update their quantity (>1) 4. Create and confirm a SO with 1 x P01 and 1 x P02 5. Deliver the products one by one 6. From the SO, create an invoice INV01 7. On INV01, remove the line associated to P02 8. Post INV01 9. From the SO, create and post the second invoice INV02 10. Print one of the invoices Error: [1] When printing INV01 (which only contains P01), the lot of P02 is also displayed. [2] When printing INV02 (which only contains P02), the lot of PO02 is not displayed When rendering an invoice, `_get_invoiced_lot_values` is called and provides all data about invoiced lots. However, there are two issues: - [1] it considers all related SML, even the ones related to a product not present in the invoice - [2] when computing the date of the last invoice, it uses the same date for all products in the invoice although it could be different depending on the product. OPW-2637107 closes odoo/odoo#83047 X-original-commit: 9ffd4a9c5755af241a7acc98bc97c790dbb1b84d Signed-off-by: William Henrotin (whe) Signed-off-by: Adrien Widart --- addons/sale_stock/models/account_move.py | 29 +++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/addons/sale_stock/models/account_move.py b/addons/sale_stock/models/account_move.py index 5cd37dff339..b380fb5910c 100644 --- a/addons/sale_stock/models/account_move.py +++ b/addons/sale_stock/models/account_move.py @@ -31,8 +31,9 @@ class AccountMove(models.Model): if self.state == 'draft': return res - sale_orders = self.mapped('invoice_line_ids.sale_line_ids.order_id') - stock_move_lines = sale_orders.mapped('picking_ids.move_ids.move_line_ids') + sale_lines = self.invoice_line_ids.sale_line_ids + sale_orders = sale_lines.order_id + stock_move_lines = sale_lines.move_ids.filtered(lambda r: r.state == 'done').move_line_ids # Get the other customer invoices and refunds. ordered_invoice_ids = sale_orders.mapped('invoice_ids')\ @@ -48,27 +49,33 @@ class AccountMove(models.Model): break i += 1 - # Get the previous invoice if any. + # Get the previous invoices if any. previous_invoices = ordered_invoice_ids[:self_index] - last_invoice = previous_invoices[-1] if len(previous_invoices) else None - # Get the incoming and outgoing sml between self.invoice_date and the previous invoice (if any). + # Get the incoming and outgoing sml between self.invoice_date and the previous invoice (if any) of the related product. write_dates = [wd for wd in self.invoice_line_ids.mapped('write_date') if wd] self_datetime = max(write_dates) if write_dates else None - last_write_dates = last_invoice and [wd for wd in last_invoice.invoice_line_ids.mapped('write_date') if wd] - last_invoice_datetime = max(last_write_dates) if last_write_dates else None + last_invoice_datetime = dict() + for product in self.invoice_line_ids.product_id: + last_invoice = previous_invoices.filtered(lambda inv: product in inv.invoice_line_ids.product_id) + last_invoice = last_invoice[-1] if last_invoice else None + last_write_dates = last_invoice and [wd for wd in last_invoice.invoice_line_ids.mapped('write_date') if wd] + last_invoice_datetime[product] = max(last_write_dates) if last_write_dates else None + def _filter_incoming_sml(ml): if ml.state == 'done' and ml.location_id.usage == 'customer' and ml.lot_id: - if last_invoice_datetime: - return last_invoice_datetime <= ml.date <= self_datetime + last_date = last_invoice_datetime.get(ml.product_id) + if last_date: + return last_date <= ml.date <= self_datetime else: return ml.date <= self_datetime return False def _filter_outgoing_sml(ml): if ml.state == 'done' and ml.location_dest_id.usage == 'customer' and ml.lot_id: - if last_invoice_datetime: - return last_invoice_datetime <= ml.date <= self_datetime + last_date = last_invoice_datetime.get(ml.product_id) + if last_date: + return last_date <= ml.date <= self_datetime else: return ml.date <= self_datetime return False