[FIX] product: _select_seller
With the new ORM, x2m records are not ordered by default. The _select_sellers implementation requires to loop on the supplier info records ordered by their _order. We fix that by sorting with a lambda with the same order set on the model. Simply using .sorted() isn't enough since it does a sort in sql, so newId records are completely removed from the resulting recordset. This is related to task 1947351 and PR 34049. We move the tests into purchase_stock and actually implement the tests proposed in the task.
This commit is contained in:
@@ -579,7 +579,7 @@ class ProductProduct(models.Model):
|
||||
'target': 'new'}
|
||||
|
||||
def _prepare_sellers(self, params):
|
||||
return self.seller_ids
|
||||
return self.seller_ids.sorted(lambda s: (s.sequence, -s.min_qty, s.price))
|
||||
|
||||
def _select_seller(self, partner_id=False, quantity=0.0, date=None, uom_id=False, params=False):
|
||||
self.ensure_one()
|
||||
|
||||
@@ -42,9 +42,7 @@ class TestPurchaseOrder(AccountingTestCase):
|
||||
})],
|
||||
}
|
||||
|
||||
|
||||
def test_00_purchase_order_flow(self):
|
||||
|
||||
# Ensure product_id_2 doesn't have res_partner_1 as supplier
|
||||
if self.partner_id in self.product_id_2.seller_ids.mapped('name'):
|
||||
id_to_remove = self.product_id_2.seller_ids.filtered(lambda r: r.name == self.partner_id).ids[0] if self.product_id_2.seller_ids.filtered(lambda r: r.name == self.partner_id) else False
|
||||
|
||||
@@ -52,3 +52,198 @@ class TestReplenishWizard(TestStockCommon):
|
||||
self.assertTrue(order_line, 'The product is not in the Purchase Order')
|
||||
self.assertEqual(order_line.product_qty, self.product_uom_qty, 'Quantities does not match')
|
||||
self.assertEqual(order_line.price_unit, self.product1_price, 'Prices does not match')
|
||||
|
||||
def test_chose_supplier_1(self):
|
||||
""" Choose supplier based on the ordered quantity and minimum price
|
||||
|
||||
replenish 10
|
||||
|
||||
1)seq1 vendor1 140 min qty 1
|
||||
2)seq2 vendor1 100 min qty 10
|
||||
-> 2) should be chosen
|
||||
"""
|
||||
product_to_buy = self.env['product.product'].create({
|
||||
'name': "Furniture Service",
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)],
|
||||
})
|
||||
vendor1 = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'})
|
||||
|
||||
supplierinfo1 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor1.id,
|
||||
'min_qty': 1,
|
||||
'price': 140,
|
||||
'sequence': 1,
|
||||
})
|
||||
supplierinfo2 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor1.id,
|
||||
'min_qty': 10,
|
||||
'price': 100,
|
||||
'sequence': 2,
|
||||
})
|
||||
|
||||
replenish_wizard = self.env['product.replenish'].create({
|
||||
'product_id': product_to_buy.id,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'quantity': 10,
|
||||
'warehouse_id': self.wh.id,
|
||||
})
|
||||
replenish_wizard.launch_replenishment()
|
||||
last_po_id = self.env['purchase.order'].search([
|
||||
('origin', 'ilike', '%Manual Replenishment%'),
|
||||
])[-1]
|
||||
self.assertEqual(last_po_id.partner_id, vendor1)
|
||||
self.assertEqual(last_po_id.order_line.price_unit, 100)
|
||||
|
||||
def test_chose_supplier_2(self):
|
||||
""" Choose supplier based on the ordered quantity and minimum price
|
||||
|
||||
replenish 10
|
||||
|
||||
1)seq1 vendor1 140 min qty 1
|
||||
2)seq2 vendor2 90 min qty 10
|
||||
3)seq3 vendor1 100 min qty 10
|
||||
-> 3) should be chosen
|
||||
"""
|
||||
product_to_buy = self.env['product.product'].create({
|
||||
'name': "Furniture Service",
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)],
|
||||
})
|
||||
vendor1 = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'})
|
||||
vendor2 = self.env['res.partner'].create({'name': 'vendor2', 'email': 'from.test2@example.com'})
|
||||
|
||||
supplierinfo1 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor1.id,
|
||||
'min_qty': 1,
|
||||
'price': 140,
|
||||
'sequence': 1,
|
||||
})
|
||||
supplierinfo2 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor2.id,
|
||||
'min_qty': 10,
|
||||
'price': 90,
|
||||
'sequence': 2,
|
||||
})
|
||||
supplierinfo3 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor1.id,
|
||||
'min_qty': 10,
|
||||
'price': 100,
|
||||
'sequence': 3,
|
||||
})
|
||||
|
||||
replenish_wizard = self.env['product.replenish'].create({
|
||||
'product_id': product_to_buy.id,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'quantity': 10,
|
||||
'warehouse_id': self.wh.id,
|
||||
})
|
||||
replenish_wizard.launch_replenishment()
|
||||
last_po_id = self.env['purchase.order'].search([
|
||||
('origin', 'ilike', '%Manual Replenishment%'),
|
||||
])[-1]
|
||||
self.assertEqual(last_po_id.partner_id, vendor1)
|
||||
self.assertEqual(last_po_id.order_line.price_unit, 100)
|
||||
|
||||
def test_chose_supplier_3(self):
|
||||
""" Choose supplier based on the ordered quantity and minimum price
|
||||
|
||||
replenish 10
|
||||
|
||||
1)seq2 vendor1 50
|
||||
2)seq1 vendor2 50
|
||||
-> 2) should be chosen
|
||||
"""
|
||||
product_to_buy = self.env['product.product'].create({
|
||||
'name': "Furniture Service",
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)],
|
||||
})
|
||||
vendor1 = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'})
|
||||
vendor2 = self.env['res.partner'].create({'name': 'vendor2', 'email': 'from.test2@example.com'})
|
||||
|
||||
supplierinfo1 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor1.id,
|
||||
'price': 50,
|
||||
'sequence': 2,
|
||||
})
|
||||
supplierinfo2 = self.env['product.supplierinfo'].create({
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'name': vendor2.id,
|
||||
'price': 50,
|
||||
'sequence': 1,
|
||||
})
|
||||
|
||||
replenish_wizard = self.env['product.replenish'].create({
|
||||
'product_id': product_to_buy.id,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'quantity': 10,
|
||||
'warehouse_id': self.wh.id,
|
||||
})
|
||||
replenish_wizard.launch_replenishment()
|
||||
last_po_id = self.env['purchase.order'].search([
|
||||
('origin', 'ilike', '%Manual Replenishment%'),
|
||||
])[-1]
|
||||
self.assertEqual(last_po_id.partner_id, vendor2)
|
||||
|
||||
def test_chose_supplier_4(self):
|
||||
""" Choose supplier based on the ordered quantity and minimum price
|
||||
|
||||
replenish 10
|
||||
|
||||
1)seq1 vendor1 100 min qty 2
|
||||
2)seq2 vendor1 60 min qty 10
|
||||
2)seq3 vendor1 80 min qty 5
|
||||
-> 2) should be chosen
|
||||
"""
|
||||
product_to_buy = self.env['product.product'].create({
|
||||
'name': "Furniture Service",
|
||||
'type': 'product',
|
||||
'categ_id': self.env.ref('product.product_category_all').id,
|
||||
'route_ids': [(4, self.env.ref('purchase_stock.route_warehouse0_buy').id, 0)],
|
||||
})
|
||||
vendor1 = self.env['res.partner'].create({'name': 'vendor1', 'email': 'from.test@example.com'})
|
||||
supplierinfo1 = self.env['product.supplierinfo'].create({
|
||||
'name': vendor1.id,
|
||||
'price': 100,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'min_qty': 2
|
||||
})
|
||||
supplierinfo2 = self.env['product.supplierinfo'].create({
|
||||
'name': vendor1.id,
|
||||
'price': 60,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'min_qty': 10
|
||||
})
|
||||
supplierinfo3 = self.env['product.supplierinfo'].create({
|
||||
'name': vendor1.id,
|
||||
'price': 80,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'min_qty': 5
|
||||
})
|
||||
replenish_wizard = self.env['product.replenish'].create({
|
||||
'product_id': product_to_buy.id,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'quantity': 10,
|
||||
'warehouse_id': self.wh.id,
|
||||
})
|
||||
replenish_wizard.launch_replenishment()
|
||||
last_po_id = self.env['purchase.order'].search([
|
||||
('origin', 'ilike', '%Manual Replenishment%'),
|
||||
])[-1]
|
||||
|
||||
self.assertEqual(last_po_id.partner_id, vendor1)
|
||||
self.assertEqual(last_po_id.order_line.price_unit, 60)
|
||||
|
||||
@@ -256,57 +256,3 @@ class TestSalePurchase(TestCommonSalePurchaseNoChart):
|
||||
self.assertEqual(purchase_line2.sale_line_id, self.sol1_service_purchase_1, "The 2nd PO line came from the SO line sol1_service_purchase_1")
|
||||
self.assertEqual(purchase_line2.product_qty, delta, "The quantity of the new PO line is the quantity added on the Sale Line, after first PO confirmation")
|
||||
|
||||
def test_choose_supplier(self):
|
||||
""" Choose supplier based on the ordered quantity and minimum price"""
|
||||
product_to_buy = self.env['product.product'].create({
|
||||
'name': "Furniture Service",
|
||||
'type': 'service',
|
||||
'service_to_purchase': True,
|
||||
})
|
||||
supplierinfo1 = self.env['product.supplierinfo'].create({
|
||||
'name': self.partner_vendor_service.id,
|
||||
'price': 100,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'min_qty': 2
|
||||
})
|
||||
supplierinfo2 = self.env['product.supplierinfo'].create({
|
||||
'name': self.partner_vendor_service.id,
|
||||
'price': 60,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'min_qty': 10
|
||||
})
|
||||
supplierinfo3 = self.env['product.supplierinfo'].create({
|
||||
'name': self.partner_vendor_service.id,
|
||||
'price': 80,
|
||||
'product_tmpl_id': product_to_buy.product_tmpl_id.id,
|
||||
'min_qty': 5
|
||||
})
|
||||
# create sale order having ordered quantity 3.
|
||||
sale_order = self.env['sale.order'].create({
|
||||
'partner_id': self.partner_customer_usd.id,
|
||||
'pricelist_id': self.pricelist_usd.id,
|
||||
'order_line': [(0, 0, {'name': product_to_buy.name,
|
||||
'product_id': product_to_buy.id,
|
||||
'product_uom_qty': 3})]
|
||||
})
|
||||
# confirm sale order
|
||||
sale_order.action_confirm()
|
||||
|
||||
# case1 for quantity 10.
|
||||
pol_from_so = self.env['purchase.order.line'].search([('sale_line_id', 'in', sale_order.order_line.ids), ('state', '!=', 'purchase')])
|
||||
pol_from_so.order_id.button_confirm() # confirm PO, so that new PO will be generated.
|
||||
# unit price of purchase order line must be 100.
|
||||
self.assertEqual(pol_from_so.price_unit, supplierinfo1.price, "For 10qty unit price must be 100.")
|
||||
|
||||
# case2. for quantity 6.
|
||||
sale_order.order_line.product_uom_qty = 8 # update sale order line having ordered quantity from 2 to 6.
|
||||
pol_from_so = self.env['purchase.order.line'].search([('sale_line_id', 'in', sale_order.order_line.ids), ('state', '!=', 'purchase')])
|
||||
pol_from_so.order_id.button_confirm() # confirm PO, so that new PO will be generated.
|
||||
# unit price of purchase order line must be 80.
|
||||
self.assertEqual(pol_from_so.price_unit, supplierinfo3.price, "For 10qty unit price must be 80.")
|
||||
|
||||
# case3. for quantity 20.
|
||||
sale_order.order_line.product_uom_qty = 20 # update sale order line having ordered quantity from 6 to 20.
|
||||
pol_from_so = self.env['purchase.order.line'].search([('sale_line_id', 'in', sale_order.order_line.ids), ('state', '!=', 'purchase')])
|
||||
# unit price of purchase order line must be 60.
|
||||
self.assertEqual(pol_from_so.price_unit, supplierinfo2.price, "For 10qty unit price must be 60.")
|
||||
|
||||
Reference in New Issue
Block a user