From 52c89adef7f49a2e12e9a4f6f9f45844bff964da Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 12 Sep 2018 14:47:15 +0200 Subject: [PATCH] [FIX] sale_stock, stock_dropshipping: ordered qty - Set a vendor on Product A - Create a SO with 1 Unit of A, set the Drop Ship route - Confirm the SO => a PO with 1 Unit is created - Change the oredered quantity to 2 The PO is updated with a total quantity of 3 instead of 2. Since the removal of procurements, the quantity is computed based on the stock moves. However, in this case, no stock move has been created since the PO is not yet confirmed. In this specific case, we fall back on the PO line quantity. The logic is similar to `_quantity_in_progress`. opw-1879118 --- addons/sale_stock/models/sale_order.py | 11 +++-- addons/stock_dropshipping/models/__init__.py | 3 +- addons/stock_dropshipping/models/sale.py | 21 +++++++++ addons/stock_dropshipping/tests/__init__.py | 2 +- .../stock_dropshipping/tests/test_dropship.py | 45 +++++++++++++++++++ 5 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 addons/stock_dropshipping/models/sale.py create mode 100644 addons/stock_dropshipping/tests/test_dropship.py diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py index bcf147c7cd4..3917e2782de 100644 --- a/addons/sale_stock/models/sale_order.py +++ b/addons/sale_stock/models/sale_order.py @@ -217,6 +217,13 @@ class SaleOrderLine(models.Model): }) return values + def _get_qty_procurement(self): + self.ensure_one() + qty = 0.0 + for move in self.move_ids.filtered(lambda r: r.state != 'cancel'): + qty += move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom, rounding_method='HALF-UP') + return qty + @api.multi def _action_launch_procurement_rule(self): """ @@ -229,9 +236,7 @@ class SaleOrderLine(models.Model): for line in self: if line.state != 'sale' or not line.product_id.type in ('consu','product'): continue - qty = 0.0 - for move in line.move_ids.filtered(lambda r: r.state != 'cancel'): - qty += move.product_uom._compute_quantity(move.product_uom_qty, line.product_uom, rounding_method='HALF-UP') + qty = line._get_qty_procurement() if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0: continue diff --git a/addons/stock_dropshipping/models/__init__.py b/addons/stock_dropshipping/models/__init__.py index c617a28246d..7d6f1be055f 100644 --- a/addons/stock_dropshipping/models/__init__.py +++ b/addons/stock_dropshipping/models/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import purchase \ No newline at end of file +from . import purchase +from . import sale diff --git a/addons/stock_dropshipping/models/sale.py b/addons/stock_dropshipping/models/sale.py new file mode 100644 index 00000000000..81f975cbce6 --- /dev/null +++ b/addons/stock_dropshipping/models/sale.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models, fields + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + purchase_line_ids = fields.One2many('purchase.order.line', 'sale_line_id') + + @api.multi + def _get_qty_procurement(self): + if not self.move_ids.filtered(lambda r: r.state != 'cancel') and self.purchase_line_ids.filtered(lambda r: r.state != 'cancel'): + qty = 0.0 + for po_line in self.purchase_line_ids.filtered(lambda r: r.state != 'cancel'): + qty += po_line.product_uom._compute_quantity(po_line.product_qty, self.product_uom, rounding_method='HALF-UP') + return qty + else: + return super(SaleOrderLine, self)._get_qty_procurement() + diff --git a/addons/stock_dropshipping/tests/__init__.py b/addons/stock_dropshipping/tests/__init__.py index 4df849a1468..7d0e80dc968 100644 --- a/addons/stock_dropshipping/tests/__init__.py +++ b/addons/stock_dropshipping/tests/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- +from . import test_dropship from . import test_stockvaluation - diff --git a/addons/stock_dropshipping/tests/test_dropship.py b/addons/stock_dropshipping/tests/test_dropship.py new file mode 100644 index 00000000000..7fb7a4ddf7c --- /dev/null +++ b/addons/stock_dropshipping/tests/test_dropship.py @@ -0,0 +1,45 @@ +from odoo.tests.common import TransactionCase + + +class TestDropship(TransactionCase): + def test_change_qty(self): + # enable the dropship and MTO route on the product + prod = self.env.ref('product.product_product_8') + dropshipping_route = self.env.ref('stock_dropshipping.route_drop_shipping') + mto_route = self.env.ref('stock.route_warehouse0_mto') + prod.write({'route_ids': [(6, 0, [dropshipping_route.id, mto_route.id])]}) + + # add a vendor + vendor1 = self.env['res.partner'].create({'name': 'vendor1'}) + seller1 = self.env['product.supplierinfo'].create({ + 'name': vendor1.id, + 'price': 8, + }) + prod.write({'seller_ids': [(6, 0, [seller1.id])]}) + + # sell one unit of this product + cust = self.env['res.partner'].create({'name': 'customer1'}) + so = self.env['sale.order'].create({ + 'partner_id': cust.id, + 'partner_invoice_id': cust.id, + 'partner_shipping_id': cust.id, + 'order_line': [(0, 0, { + 'name': prod.name, + 'product_id': prod.id, + 'product_uom_qty': 1.00, + 'product_uom': prod.uom_id.id, + 'price_unit': 12, + })], + 'pricelist_id': self.env.ref('product.list0').id, + 'picking_policy': 'direct', + }) + so.action_confirm() + po = self.env['purchase.order'].search([('group_id', '=', so.procurement_group_id.id)]) + po_line = po.order_line + + # Check the qty on the P0 + self.assertAlmostEqual(po_line.product_qty, 1.00) + + # Update qty on SO and check PO + so.order_line.product_uom_qty = 2.00 + self.assertAlmostEqual(po_line.product_qty, 2.00)