282 lines
12 KiB
Python
282 lines
12 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from unittest.mock import patch, DEFAULT
|
|
from odoo import Command
|
|
from odoo.exceptions import UserError
|
|
from odoo.tests import Form
|
|
from odoo.tests.common import TransactionCase
|
|
|
|
|
|
class TestCarrierPropagation(TransactionCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.warehouse = cls.env.ref("stock.warehouse0")
|
|
|
|
# Set Warehouse as multi steps delivery
|
|
cls.warehouse.delivery_steps = "pick_pack_ship"
|
|
|
|
# Create a delivery product and its carrier
|
|
cls.ProductProduct = cls.env['product.product']
|
|
cls.SaleOrder = cls.env['sale.order']
|
|
cls.StockMove = cls.env["stock.move"]
|
|
|
|
cls.partner_propagation = cls.env['res.partner'].create({
|
|
'name': 'My Carrier Propagation Customer'})
|
|
|
|
cls.product_uom_unit = cls.env.ref('uom.product_uom_unit')
|
|
cls.product_delivery_normal = cls.env['product.product'].create({
|
|
'name': 'Normal Delivery Charges',
|
|
'invoice_policy': 'order',
|
|
'type': 'service',
|
|
'list_price': 10.0,
|
|
'categ_id': cls.env.ref('delivery.product_category_deliveries').id,
|
|
})
|
|
cls.normal_delivery = cls.env['delivery.carrier'].create({
|
|
'name': 'Normal Delivery Charges',
|
|
'fixed_price': 10,
|
|
'delivery_type': 'fixed',
|
|
'product_id': cls.product_delivery_normal.id,
|
|
})
|
|
cls.customer_location = cls.env.ref("stock.stock_location_customers")
|
|
cls.output_location = cls.env.ref("stock.stock_location_output")
|
|
cls.super_product = cls.ProductProduct.create({
|
|
'name': 'Super Product',
|
|
'invoice_policy': 'delivery',
|
|
})
|
|
mto_route = cls.env.ref('stock.route_warehouse0_mto')
|
|
mto_route.active = True
|
|
cls.warehouse.mto_pull_id.procure_method = "make_to_stock"
|
|
cls.mto_product = cls.ProductProduct.create({
|
|
'name': 'MTO Product',
|
|
'invoice_policy': 'delivery',
|
|
'route_ids': [(6, 0, mto_route.ids)],
|
|
})
|
|
cls.rule_pack = cls.warehouse.delivery_route_id.rule_ids.filtered(lambda r: r.picking_type_id == cls.warehouse.pack_type_id)
|
|
|
|
def test_carrier_no_propagation(self):
|
|
"""
|
|
Set the carrier propagation to False on stock.rule
|
|
Create a Sale Order, confirm it
|
|
Check that the carrier is set on the OUT
|
|
Check that the carrier is not set on the PACK
|
|
"""
|
|
self.rule_pack.propagate_carrier = False
|
|
|
|
so = self.SaleOrder.create({
|
|
'name': 'Sale order',
|
|
'partner_id': self.partner_propagation.id,
|
|
'partner_invoice_id': self.partner_propagation.id,
|
|
'order_line': [
|
|
(0, 0, {'name': self.super_product.name, 'product_id': self.super_product.id, 'product_uom_qty': 1, 'price_unit': 1,}),
|
|
]
|
|
})
|
|
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
|
|
'default_order_id': so.id,
|
|
'default_carrier_id': self.normal_delivery.id,
|
|
}))
|
|
choose_delivery_carrier = delivery_wizard.save()
|
|
choose_delivery_carrier.button_confirm()
|
|
# Confirm the SO
|
|
so.action_confirm()
|
|
|
|
pick = so.picking_ids
|
|
self.assertEqual(self.normal_delivery, pick.carrier_id)
|
|
pick.button_validate()
|
|
|
|
pack = pick.move_ids.move_dest_ids.picking_id
|
|
self.assertFalse(pack.carrier_id)
|
|
|
|
def test_carrier_propagation(self):
|
|
"""
|
|
Set the carrier propagation to True on stock.rule
|
|
Create a Sale Order, confirm it
|
|
Check that the carrier is set on the OUT
|
|
Check that the carrier is set on the PACK
|
|
"""
|
|
self.rule_pack.propagate_carrier = True
|
|
|
|
for product in [self.super_product, self.mto_product]:
|
|
so = self.SaleOrder.create({
|
|
'name': 'Sale order',
|
|
'partner_id': self.partner_propagation.id,
|
|
'partner_invoice_id': self.partner_propagation.id,
|
|
'order_line': [
|
|
(0, 0, {'name': product.name, 'product_id': product.id, 'product_uom_qty': 1, 'price_unit': 1,}),
|
|
]
|
|
})
|
|
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
|
|
'default_order_id': so.id,
|
|
'default_carrier_id': self.normal_delivery.id,
|
|
}))
|
|
choose_delivery_carrier = delivery_wizard.save()
|
|
choose_delivery_carrier.button_confirm()
|
|
# Confirm the SO
|
|
so.action_confirm()
|
|
|
|
pick = so.picking_ids
|
|
self.assertEqual(self.normal_delivery, pick.carrier_id)
|
|
pick.button_validate()
|
|
|
|
pack = pick.move_ids.move_dest_ids.picking_id
|
|
self.assertEqual(self.normal_delivery, pack.carrier_id)
|
|
pack.button_validate()
|
|
|
|
ship = pack.move_ids.move_dest_ids.picking_id
|
|
self.assertEqual(self.normal_delivery, ship.carrier_id)
|
|
|
|
def test_route_based_on_carrier_delivery(self):
|
|
"""
|
|
Check that the route on the sale order line is selected as per the first priority even if route on shipping mehod is present
|
|
Also, Check that the route on the shipping method is selected if there is no route selected on sale order line
|
|
"""
|
|
route1 = self.env['stock.route'].create({
|
|
'name': 'Route1',
|
|
'sale_selectable' : True,
|
|
'shipping_selectable': True,
|
|
'warehouse_ids': [Command.link(self.env.ref("stock.warehouse0").id)],
|
|
'rule_ids': [Command.create({
|
|
'name': 'rule1',
|
|
'location_src_id': self.warehouse.lot_stock_id.id,
|
|
'location_dest_id': self.customer_location.id,
|
|
'company_id': self.env.company.id,
|
|
'action': 'pull',
|
|
'auto': 'transparent',
|
|
'picking_type_id': self.ref('stock.picking_type_out'),
|
|
})],
|
|
})
|
|
shelf1_location = self.env['stock.location'].create({
|
|
'name': 'shelf1',
|
|
'usage': 'internal',
|
|
'location_id': self.env.ref('stock.stock_location_stock').id,
|
|
})
|
|
route2 = self.env['stock.route'].create({
|
|
'name': 'Route2',
|
|
'sale_selectable' : True,
|
|
'shipping_selectable':True,
|
|
'warehouse_ids': [Command.link(self.env.ref("stock.warehouse0").id)],
|
|
'rule_ids': [Command.create({
|
|
'name': 'rule2',
|
|
'location_src_id': shelf1_location.id,
|
|
'location_dest_id': self.customer_location.id,
|
|
'company_id': self.env.company.id,
|
|
'action': 'pull',
|
|
'auto': 'transparent',
|
|
'picking_type_id': self.ref('stock.picking_type_out'),
|
|
})],
|
|
})
|
|
self.normal_delivery.write({
|
|
"route_ids": [Command.link(route2.id)]
|
|
})
|
|
|
|
sale_order1 = self.SaleOrder.create({
|
|
'partner_id': self.partner_propagation.id,
|
|
'order_line': [Command.create({
|
|
'name': 'Cable Management Box',
|
|
'product_id': self.super_product.id,
|
|
'product_uom_qty': 2,
|
|
'product_uom': self.product_uom_unit.id,
|
|
'price_unit': 750.00,
|
|
'route_id' : route1.id,
|
|
})],
|
|
})
|
|
|
|
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
|
|
'default_order_id': sale_order1.id,
|
|
'default_carrier_id': self.normal_delivery.id,
|
|
}))
|
|
choose_delivery_carrier = delivery_wizard.save()
|
|
choose_delivery_carrier.button_confirm()
|
|
|
|
sale_order1.action_confirm()
|
|
self.assertEqual(sale_order1.picking_ids.location_id, route1.rule_ids.location_src_id)
|
|
|
|
# check route without add in sale order line
|
|
sale_order2 = self.SaleOrder.create({
|
|
'partner_id': self.partner_propagation.id,
|
|
'order_line': [Command.create({
|
|
'name': 'Cable Management Box',
|
|
'product_id': self.super_product.id,
|
|
'product_uom_qty': 2,
|
|
'product_uom': self.product_uom_unit.id,
|
|
'price_unit': 750.00,
|
|
})],
|
|
})
|
|
|
|
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
|
|
'default_order_id': sale_order2.id,
|
|
'default_carrier_id': self.normal_delivery.id,
|
|
}))
|
|
choose_delivery_carrier = delivery_wizard.save()
|
|
choose_delivery_carrier.button_confirm()
|
|
|
|
sale_order2.action_confirm()
|
|
self.assertEqual(sale_order2.picking_ids.location_id, route2.rule_ids.location_src_id)
|
|
|
|
def test_carrier_picking_batch_validation(self):
|
|
"""
|
|
Create 2 delivery orders with carriers. Make them respectively
|
|
valid and invalid on the carrier side. Validate the pickings in batch
|
|
Since the pickings are processed unbatched on the carrier side the
|
|
"UserError" of the invalid picking can not be raised and should be
|
|
replaced by a warning activity.
|
|
"""
|
|
self.warehouse.delivery_steps = "ship_only"
|
|
alien = self.env['res.users'].create({
|
|
'login': 'Mars Man',
|
|
'name': 'Spleton',
|
|
'email': 'alien@mars.com',
|
|
})
|
|
super_product_2 = self.ProductProduct.create({
|
|
'name': 'Super Product 2',
|
|
'invoice_policy': 'delivery',
|
|
})
|
|
sale_orders = self.env['sale.order'].create([
|
|
{
|
|
'partner_id': self.partner_propagation.id,
|
|
'order_line': [
|
|
Command.create({
|
|
'product_id': self.super_product.id
|
|
}),
|
|
]
|
|
},
|
|
{
|
|
'partner_id': self.partner_propagation.id,
|
|
'order_line': [
|
|
Command.create({
|
|
'product_id': super_product_2.id
|
|
}),
|
|
]
|
|
},
|
|
])
|
|
for so in sale_orders:
|
|
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
|
|
'default_order_id': so.id,
|
|
'default_carrier_id': self.normal_delivery.id,
|
|
}))
|
|
choose_delivery_carrier = delivery_wizard.save()
|
|
choose_delivery_carrier.button_confirm()
|
|
|
|
def fail_send_to_shipper(pick):
|
|
# side effect to throw an error for a given picking but resolve the normal call for the other
|
|
def _throw_error_on_chosen_picking(self):
|
|
if self == pick:
|
|
raise UserError("Something went wrong, parcel not returned from Sendcloud: {'weight': ['The weight must be less than 10.001 kg']}")
|
|
else:
|
|
return DEFAULT
|
|
return _throw_error_on_chosen_picking
|
|
|
|
sale_orders.action_confirm()
|
|
for i in range(0, len(sale_orders)):
|
|
# check that a delivery was created for the associated carrier
|
|
self.assertEqual(sale_orders[i].picking_ids.carrier_id.id, sale_orders[i].carrier_id.id)
|
|
pickings = sale_orders.picking_ids
|
|
pickings.action_assign()
|
|
picking_class = 'odoo.addons.stock_delivery.models.stock_picking.StockPicking'
|
|
with patch(picking_class + '.send_to_shipper', new=fail_send_to_shipper(pickings[1])):
|
|
pickings.with_user(alien).button_validate()
|
|
# both pickings should be validated but and activity should have been created for the invalid picking
|
|
self.assertEqual(pickings.mapped('state'), ['done', 'done'])
|
|
self.assertTrue(self.env['mail.activity'].search([('res_model', '=', 'stock.picking'), ('res_id', '=', pickings[1].id), ('user_id', '=', alien.id)], limit=1))
|