532 lines
20 KiB
Python
Executable File
532 lines
20 KiB
Python
Executable File
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
from datetime import datetime
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo.exceptions import UserError
|
|
|
|
from odoo.addons.sale.tests.common import TestSaleCommonBase
|
|
|
|
|
|
class TestSaleStock(TestSaleCommonBase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.partner = cls.env.ref("base.res_partner_1")
|
|
cls.product = cls.env.ref("product.product_delivery_01")
|
|
cls.product2 = cls.env.ref("product.product_delivery_02")
|
|
cls.product3 = cls.env.ref("product.product_order_01")
|
|
cls.carrier1 = cls.env.ref("delivery.delivery_carrier")
|
|
cls.carrier2 = cls.env.ref("delivery.delivery_local_delivery")
|
|
cls.stock_location = cls.env.ref("stock.stock_location_stock")
|
|
cls.env["stock.quant"]._update_available_quantity(
|
|
cls.product, cls.stock_location, 100
|
|
)
|
|
cls.env.user_demo = cls.env.ref("base.user_demo")
|
|
|
|
def _manual_delivery_wizard(self, records, vals=None):
|
|
if not vals:
|
|
vals = {}
|
|
return (
|
|
self.env["manual.delivery"]
|
|
.with_context(
|
|
active_model=records._name,
|
|
active_ids=records.ids,
|
|
)
|
|
.create(vals)
|
|
)
|
|
|
|
def test_00_sale_manual_delivery(self):
|
|
"""
|
|
Test SO's manual delivery; we do it with a user without admin rights
|
|
"""
|
|
model_user_order = self.env["sale.order"].with_user(self.env.user_demo)
|
|
order = model_user_order.create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 5.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
)
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
# confirm our standard so, check the picking
|
|
order.action_confirm()
|
|
self.assertFalse(
|
|
order.picking_ids,
|
|
'No picking should be created for "manual delivery" orders',
|
|
)
|
|
# Raise error when user try to modify sale order in confirmd stage.
|
|
with self.assertRaises(UserError):
|
|
order.write({"manual_delivery": False})
|
|
# open the manual delivery wizard
|
|
action = order.action_manual_delivery_wizard()
|
|
self.assertEqual(action["res_model"], "manual.delivery")
|
|
# create a manual delivery for all ordered quantity
|
|
self._manual_delivery_wizard(order).confirm()
|
|
# check picking is created
|
|
self.assertTrue(
|
|
order.picking_ids,
|
|
'Picking should be created after "manual delivery" wizard call',
|
|
)
|
|
# create a manual delivery, nothing left to ship
|
|
wizard = self._manual_delivery_wizard(order)
|
|
self.assertFalse(
|
|
wizard.line_ids,
|
|
"After picking creation for all products, "
|
|
"no lines should be left in the wizard",
|
|
)
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids), 1.0, "Picking number should remain 1.0"
|
|
)
|
|
|
|
def test_01_sale_standard_delivery(self):
|
|
"""
|
|
Test SO's standard delivery
|
|
"""
|
|
order = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 5.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
)
|
|
],
|
|
"manual_delivery": False,
|
|
}
|
|
)
|
|
# confirm our standard so, check the picking
|
|
order.action_confirm()
|
|
self.assertTrue(
|
|
order.picking_ids,
|
|
'Picking should be created for "standard delivery" orders',
|
|
)
|
|
# deliver completely
|
|
pick = order.picking_ids
|
|
pick.action_assign()
|
|
pick.move_line_ids.write({"quantity": 5})
|
|
pick.button_validate()
|
|
# Check quantity delivered
|
|
del_qty = sum(sol.qty_delivered for sol in order.order_line)
|
|
self.assertEqual(del_qty, 5.0, "Delivery quantity doesn't match")
|
|
|
|
def test_02_sale_various_manual_delivery(self):
|
|
"""
|
|
Test SO's various manual delivery
|
|
"""
|
|
order = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 5.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
)
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
# confirm our standard so, check the picking
|
|
order.action_confirm()
|
|
self.assertFalse(
|
|
order.picking_ids,
|
|
'No picking should be created for "manual delivery" orders',
|
|
)
|
|
# create a manual delivery for part of ordered quantity
|
|
wizard = self._manual_delivery_wizard(order)
|
|
wizard.line_ids.write({"quantity": 2.0})
|
|
wizard.confirm()
|
|
# checking has_pending_delivery for Create Delivery button to appear
|
|
self.assertTrue(order.has_pending_delivery)
|
|
# check picking is created
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
1,
|
|
'Picking should be created after "manual delivery" wizard call',
|
|
)
|
|
# deliver completely
|
|
pick = order.picking_ids
|
|
pick.action_assign()
|
|
pick.move_line_ids.write({"quantity": 2})
|
|
pick.button_validate()
|
|
# Check quantity delivered
|
|
del_qty = sum(sol.qty_delivered for sol in order.order_line)
|
|
self.assertEqual(del_qty, 2.0, "Delivery quantity doesn't match")
|
|
# a manual delivery with qty 0 shouldn't do anything
|
|
wizard = self._manual_delivery_wizard(order)
|
|
wizard.line_ids.write({"quantity": 0.0})
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
1.0,
|
|
"No picking should've been created",
|
|
)
|
|
# try to create a manual delivery with more quantity than the ordered
|
|
wizard = self._manual_delivery_wizard(order)
|
|
with self.assertRaises(UserError):
|
|
wizard.line_ids.write({"quantity": 10.0})
|
|
wizard.confirm()
|
|
# create a manual delivery, 3.0 left to ship
|
|
wizard = self._manual_delivery_wizard(order)
|
|
wizard.line_ids.write({"quantity": 3.0})
|
|
wizard.confirm()
|
|
# checking has_pending_delivery for Create Delivery button to hide
|
|
self.assertFalse(order.has_pending_delivery)
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
2.0,
|
|
"Picking number doesn't match",
|
|
)
|
|
|
|
def test_03_sale_selected_lines(self):
|
|
"""
|
|
Test SO's various manual delivery
|
|
"""
|
|
order1 = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 1.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
)
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
order2 = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product2.name,
|
|
"product_id": self.product2.id,
|
|
"product_uom_qty": 2.0,
|
|
"product_uom": self.product2.uom_id.id,
|
|
"price_unit": self.product2.list_price,
|
|
},
|
|
)
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
order3 = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product3.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 3.0,
|
|
"product_uom": self.product3.uom_id.id,
|
|
"price_unit": self.product3.list_price,
|
|
},
|
|
)
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
# confirm our standard so, check the picking
|
|
order1.action_confirm()
|
|
order2.action_confirm()
|
|
order3.action_confirm()
|
|
some_lines = order1.order_line | order3.order_line
|
|
all_lines = order1.order_line | order2.order_line | order3.order_line
|
|
# create a manual delivery for part of ordered quantity
|
|
wizard = self._manual_delivery_wizard(some_lines)
|
|
self.assertEqual(sum(wizard.line_ids.mapped("quantity")), 4.0)
|
|
wizard.confirm()
|
|
# check picking is created
|
|
self.assertTrue(
|
|
order3.picking_ids,
|
|
'Picking should be created after "manual delivery" wizard call',
|
|
)
|
|
self.assertEqual(
|
|
len(order3.picking_ids.move_ids),
|
|
1,
|
|
"Different sales orders should still create different pickings",
|
|
)
|
|
self.assertFalse(
|
|
order2.picking_ids,
|
|
'Picking should not be created after "manual delivery" wizard call',
|
|
)
|
|
# test action undelivered
|
|
undelivered = self.env["sale.order.line"].search(
|
|
[
|
|
("qty_to_procure", ">", 0),
|
|
("state", "=", "sale"),
|
|
("id", "in", all_lines.ids),
|
|
]
|
|
)
|
|
self.assertEqual(
|
|
undelivered,
|
|
order2.order_line,
|
|
"Bad pending qty to deliver filter",
|
|
)
|
|
|
|
def test_03_sale_multi_delivery(self):
|
|
self.env["stock.quant"]._update_available_quantity(
|
|
self.product2, self.stock_location, 100
|
|
)
|
|
order = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 10.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
),
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product2.name,
|
|
"product_id": self.product2.id,
|
|
"product_uom_qty": 10.0,
|
|
"product_uom": self.product2.uom_id.id,
|
|
"price_unit": self.product2.list_price,
|
|
},
|
|
),
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
|
|
# confirm our standard so, check the picking
|
|
order.action_confirm()
|
|
self.assertFalse(
|
|
order.picking_ids,
|
|
'No picking should be created for "manual delivery" orders',
|
|
)
|
|
# create a manual delivery for part of ordered quantity
|
|
date_now = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
|
wizard = self._manual_delivery_wizard(
|
|
order.order_line[0],
|
|
{"carrier_id": order.carrier_id.id, "date_planned": date_now},
|
|
)
|
|
wizard.line_ids.write({"quantity": 2.0})
|
|
wizard.confirm()
|
|
# check picking is created
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
1,
|
|
'Picking should be created after "manual delivery" wizard call',
|
|
)
|
|
first_picking = order.picking_ids
|
|
self.assertEqual(
|
|
first_picking.scheduled_date.replace(
|
|
hour=0, minute=0, second=0, microsecond=0
|
|
),
|
|
date_now,
|
|
)
|
|
# create a second manual delivery for next week
|
|
date_next_week = date_now + relativedelta(weeks=1)
|
|
wizard = self._manual_delivery_wizard(
|
|
order.order_line[1],
|
|
{"carrier_id": order.carrier_id.id, "date_planned": date_next_week},
|
|
)
|
|
wizard.line_ids.write({"quantity": 3.0})
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
2,
|
|
"Sale Manual Delivery: second picking should be created after"
|
|
' "manual delivery" wizard call with different date',
|
|
)
|
|
second_picking = order.picking_ids - first_picking
|
|
self.assertEqual(
|
|
second_picking.scheduled_date.replace(
|
|
hour=0, minute=0, second=0, microsecond=0
|
|
),
|
|
date_next_week,
|
|
)
|
|
# create a third manual delivery for today (should be mixed with first)
|
|
new_date_now = datetime.now()
|
|
wizard = self._manual_delivery_wizard(
|
|
order.order_line[0],
|
|
{"carrier_id": order.carrier_id.id, "date_planned": new_date_now},
|
|
)
|
|
wizard.line_ids.write({"quantity": 5.0})
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
2,
|
|
"Sale Manual Delivery: new moves should be merged in first picking"
|
|
' after "manual delivery" wizard call with same date',
|
|
)
|
|
self.assertEqual(
|
|
sum(first_picking.mapped("move_ids.product_uom_qty")),
|
|
7,
|
|
)
|
|
|
|
def test_04_sale_single_picking(self):
|
|
"""
|
|
Test SO's various manual delivery
|
|
"""
|
|
order = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 1.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
),
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product2.name,
|
|
"product_id": self.product2.id,
|
|
"product_uom_qty": 2.0,
|
|
"product_uom": self.product2.uom_id.id,
|
|
"price_unit": self.product2.list_price,
|
|
},
|
|
),
|
|
],
|
|
"manual_delivery": True,
|
|
}
|
|
)
|
|
# confirm our standard so, check the picking
|
|
order.action_confirm()
|
|
# create a manual delivery for part of ordered quantity
|
|
wizard = self._manual_delivery_wizard(order.order_line)
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids), 1.0, "Delivery: picking number should be 1.0"
|
|
)
|
|
|
|
def test_05_sale_multi_carrier(self):
|
|
order = self.env["sale.order"].create(
|
|
{
|
|
"partner_id": self.partner.id,
|
|
"partner_invoice_id": self.partner.id,
|
|
"partner_shipping_id": self.partner.id,
|
|
"order_line": [
|
|
(
|
|
0,
|
|
0,
|
|
{
|
|
"name": self.product.name,
|
|
"product_id": self.product.id,
|
|
"product_uom_qty": 10.0,
|
|
"product_uom": self.product.uom_id.id,
|
|
"price_unit": self.product.list_price,
|
|
},
|
|
),
|
|
],
|
|
"manual_delivery": True,
|
|
"carrier_id": self.carrier1.id,
|
|
}
|
|
)
|
|
# confirm our standard so, check the picking
|
|
order.action_confirm()
|
|
# create a manual delivery for part of ordered quantity
|
|
wizard = self._manual_delivery_wizard(order, {"carrier_id": self.carrier1.id})
|
|
wizard.line_ids.write({"quantity": 2.0})
|
|
wizard.confirm()
|
|
# check picking is created
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
1,
|
|
'Picking should be created after "manual delivery" wizard call',
|
|
)
|
|
first_picking = order.picking_ids
|
|
self.assertEqual(
|
|
first_picking.carrier_id,
|
|
order.carrier_id,
|
|
"Picking carrier should be the one in the order",
|
|
)
|
|
# create a second manual delivery with a different carrier
|
|
wizard = self._manual_delivery_wizard(order, {"carrier_id": self.carrier2.id})
|
|
wizard.line_ids.write({"quantity": 2.0})
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
2,
|
|
"A different picking should've been created, as the carrier is different",
|
|
)
|
|
second_picking = order.picking_ids - first_picking
|
|
self.assertEqual(
|
|
second_picking.carrier_id,
|
|
self.carrier2,
|
|
"Picking carrier should be the one selected",
|
|
)
|
|
# create a third manual delivery for (should be mixed with first)
|
|
wizard = self._manual_delivery_wizard(order, {"carrier_id": self.carrier1.id})
|
|
wizard.line_ids.write({"quantity": 2.0})
|
|
wizard.confirm()
|
|
self.assertEqual(
|
|
len(order.picking_ids),
|
|
2,
|
|
"The first picking should be re-used",
|
|
)
|