From 716437be2d91d36da31ade2104e5eb234deacc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 28 Sep 2024 18:05:21 +0200 Subject: [PATCH] Link stock moves with invoice lines only for the same quantity sign as the order line When invoice lines are created to correct invoices quantity, it should not be linked to stock moves because it comes from a stock move being cancelled. Closes #12972 (grafted from 20c538f39c871bacc0486b8506957229268f59cd) --HG-- branch : 7.0 --- modules/purchase/purchase.py | 14 +++++++++++--- modules/sale/sale.py | 11 +++++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/modules/purchase/purchase.py b/modules/purchase/purchase.py index cb3d50d63e..5eec0051e7 100644 --- a/modules/purchase/purchase.py +++ b/modules/purchase/purchase.py @@ -1,6 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime +import math from collections import defaultdict from decimal import Decimal from itertools import chain, groupby @@ -34,6 +35,10 @@ from .exceptions import ( PartyLocationError, PurchaseMoveQuantity, PurchaseQuotationError) +def samesign(a, b): + return math.copysign(a, b) == a + + def get_shipments_returns(model_name): "Computes the returns or shipments" def method(self, name): @@ -1727,7 +1732,8 @@ class Line(sequence_ordered(), ModelSQL, ModelView): gettext('purchase' '.msg_purchase_missing_account_expense', purchase=self.purchase.rec_name)) - invoice_line.stock_moves = self._get_invoice_line_moves() + if samesign(self.quantity, invoice_line.quantity): + invoice_line.stock_moves = self._get_invoice_line_moves() return [invoice_line] def _get_invoice_line_quantity(self): @@ -1871,9 +1877,11 @@ class Line(sequence_ordered(), ModelSQL, ModelView): def _get_move_invoice_lines(self, move_type): 'Return the invoice lines that should be shipped' if self.purchase.invoice_method in {'order', 'manual'}: - return [l for l in self.invoice_lines] + lines = self.invoice_lines else: - return [l for l in self.invoice_lines if not l.stock_moves] + lines = filter(lambda l: not l.stock_moves, self.invoice_lines) + return list(filter( + lambda l: samesign(self.quantity, l.quantity), lines)) def set_actual_quantity(self): pool = Pool() diff --git a/modules/sale/sale.py b/modules/sale/sale.py index 39a90e637c..595343ac4d 100644 --- a/modules/sale/sale.py +++ b/modules/sale/sale.py @@ -1,6 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime +import math from collections import defaultdict from decimal import Decimal from functools import partial @@ -34,6 +35,10 @@ from .exceptions import ( SaleValidationError) +def samesign(a, b): + return math.copysign(a, b) == a + + def get_shipments_returns(model_name): "Computes the returns or shipments" def method(self, name): @@ -1757,7 +1762,8 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView): raise AccountError( gettext('sale.msg_sale_missing_account_revenue', sale=self.sale.rec_name)) - invoice_line.stock_moves = self._get_invoice_line_moves() + if samesign(self.quantity, invoice_line.quantity): + invoice_line.stock_moves = self._get_invoice_line_moves() return [invoice_line] def _get_invoice_line_quantity(self): @@ -1924,7 +1930,8 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView): and invoice_line.invoice.state == 'paid'): if invoice_line.moved_quantity < invoice_line.quantity: invoice_lines.append(invoice_line) - return invoice_lines + return list(filter( + lambda l: samesign(self.quantity, l.quantity), invoice_lines)) def set_actual_quantity(self): pool = Pool()