[IMP] stock: add ask-always-never setting for backorder
In picking type, we introduce a new setting ask-always-never setting for creating backorder. When a backorder is needed, the behaviour will be different according to this setting: - ask: popup a wizard to ask if a backorder is needed - always: generate backorder automatically - never: no backorder The main reasoning behind this change is that there are some scenarios in which operators always create backorders (e.g. by validating the transfer after scanning a pallet and setting quantities). Hence, always asking if the user (operator) wants to create a backorder can be confusing. task-2648993 Part-of: odoo/odoo#83462
This commit is contained in:
committed by
yhu-odoo
parent
c7c96d61e9
commit
047bfa7536
@@ -88,6 +88,13 @@ class PickingType(models.Model):
|
||||
company_id = fields.Many2one(
|
||||
'res.company', 'Company', required=True,
|
||||
default=lambda s: s.env.company.id, index=True)
|
||||
create_backorder = fields.Selection(
|
||||
[('ask', 'Ask'), ('always', 'Always'), ('never', 'Never')],
|
||||
'Create Backorder', required=True, default='ask',
|
||||
help="When validating a transfer:\n"
|
||||
" * Ask: users are asked to choose if they want to make a backorder for remaining products\n"
|
||||
" * Always: a backorder is automatically created for the remaining products\n"
|
||||
" * Never: remaining products are cancelled")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -1010,12 +1017,10 @@ class Picking(models.Model):
|
||||
return res
|
||||
|
||||
# Call `_action_done`.
|
||||
pickings_not_to_backorder = self.filtered(lambda p: p.picking_type_id.create_backorder == 'never')
|
||||
if self.env.context.get('picking_ids_not_to_backorder'):
|
||||
pickings_not_to_backorder = self.browse(self.env.context['picking_ids_not_to_backorder'])
|
||||
pickings_to_backorder = self - pickings_not_to_backorder
|
||||
else:
|
||||
pickings_not_to_backorder = self.env['stock.picking']
|
||||
pickings_to_backorder = self
|
||||
pickings_not_to_backorder |= self.browse(self.env.context['picking_ids_not_to_backorder'])
|
||||
pickings_to_backorder = self - pickings_not_to_backorder
|
||||
pickings_not_to_backorder.with_context(cancel_backorder=True)._action_done()
|
||||
pickings_to_backorder.with_context(cancel_backorder=False)._action_done()
|
||||
|
||||
@@ -1106,6 +1111,8 @@ class Picking(models.Model):
|
||||
prec = self.env["decimal.precision"].precision_get("Product Unit of Measure")
|
||||
backorder_pickings = self.browse()
|
||||
for picking in self:
|
||||
if picking.picking_type_id.create_backorder != 'ask':
|
||||
continue
|
||||
quantity_todo = {}
|
||||
quantity_done = {}
|
||||
for move in picking.move_ids.filtered(lambda m: m.state != "cancel"):
|
||||
|
||||
@@ -1670,7 +1670,7 @@ class TestStockFlow(TestStockCommon):
|
||||
backorder_wizard.process_cancel_backorder()
|
||||
|
||||
# Checking that no backorders were attached to the picking
|
||||
self.assertFalse(picking.backorder_id)
|
||||
self.assertFalse(picking.backorder_ids)
|
||||
|
||||
# Checking that the original move is still in the same picking
|
||||
self.assertEqual(move_a.picking_id.id, picking.id)
|
||||
@@ -1690,6 +1690,73 @@ class TestStockFlow(TestStockCommon):
|
||||
# Checking that the canceled move is in the original picking
|
||||
self.assertIn(move_canceled.id, picking.move_ids.mapped('id'))
|
||||
|
||||
def test_backorder_setting(self):
|
||||
"""Create 3 pickings with each has different backorder settings on its
|
||||
picking type. Check the backorder behavior for each picking.
|
||||
"""
|
||||
picking_type_ask = self.env['stock.picking.type'].browse(self.picking_type_in)
|
||||
picking_type_ask.create_backorder = 'ask'
|
||||
picking_type_always = picking_type_ask.copy({
|
||||
'sequence_code': 'always',
|
||||
'create_backorder': 'always',
|
||||
})
|
||||
picking_type_never = picking_type_ask.copy({
|
||||
'sequence_code': 'never',
|
||||
'create_backorder': 'never',
|
||||
})
|
||||
|
||||
picking_ask = self.PickingObj.create({
|
||||
'picking_type_id': picking_type_ask.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location})
|
||||
self.MoveObj.create({
|
||||
'name': self.productA.name,
|
||||
'product_id': self.productA.id,
|
||||
'product_uom_qty': 10,
|
||||
'product_uom': self.productA.uom_id.id,
|
||||
'picking_id': picking_ask.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location})
|
||||
picking_always = self.PickingObj.create({
|
||||
'picking_type_id': picking_type_always.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location})
|
||||
self.MoveObj.create({
|
||||
'name': self.productA.name,
|
||||
'product_id': self.productA.id,
|
||||
'product_uom_qty': 10,
|
||||
'product_uom': self.productA.uom_id.id,
|
||||
'picking_id': picking_always.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location})
|
||||
picking_never = self.PickingObj.create({
|
||||
'picking_type_id': picking_type_never.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location})
|
||||
self.MoveObj.create({
|
||||
'name': self.productA.name,
|
||||
'product_id': self.productA.id,
|
||||
'product_uom_qty': 10,
|
||||
'product_uom': self.productA.uom_id.id,
|
||||
'picking_id': picking_never.id,
|
||||
'location_id': self.supplier_location,
|
||||
'location_dest_id': self.stock_location})
|
||||
|
||||
pickings = picking_ask | picking_always | picking_never
|
||||
pickings.action_confirm()
|
||||
# Only 4 items are processed in each picking
|
||||
pickings.move_ids.move_line_ids.qty_done = 4
|
||||
res_dict = pickings.button_validate()
|
||||
backorder_wizard = Form(self.env['stock.backorder.confirmation'].with_context(res_dict['context'])).save()
|
||||
|
||||
self.assertEqual(backorder_wizard.pick_ids, picking_ask, "Only ask backorder for picking with setting 'set'")
|
||||
backorder_wizard.process_cancel_backorder()
|
||||
|
||||
self.assertEqual(pickings.mapped('state'), ['done', 'done', 'done'])
|
||||
self.assertFalse(picking_ask.backorder_ids)
|
||||
self.assertTrue(picking_always.backorder_ids, "Picking with setting 'always' should have backorder created")
|
||||
self.assertFalse(picking_never.backorder_ids, "Picking with setting 'never' should have no backorder created")
|
||||
|
||||
def test_transit_multi_companies(self):
|
||||
""" Ensure that inter company rules set the correct company on picking
|
||||
and their moves.
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<field name="code"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field attrs='{"invisible": [("code", "not in", ["incoming", "outgoing", "internal"])]}' name="return_picking_type_id"/>
|
||||
<field name="create_backorder" />
|
||||
<field name="show_operations"/>
|
||||
<field name="show_reserved" attrs="{'invisible': [('code', '!=', 'incoming')]}"/>
|
||||
</group>
|
||||
|
||||
Reference in New Issue
Block a user