Commit 6efb7bc9 authored by Cédric Krier's avatar Cédric Krier
Browse files

Store warehouse locations on shipments

This ensures that the domain based on warehouse location stays valid even if
the warehouse configuration is changed after the creation of the shipment.

Closes #11974
parent e3aa1151f4e8
Pipeline #61579 passed with stages
in 25 minutes and 35 seconds
......@@ -879,6 +879,7 @@
}
values.update(dict(key))
shipment = Shipment(**values)
shipment.on_change_warehouse()
if Shipment.__name__ == 'stock.shipment.out':
if self.shipment_address == self.warehouse.address:
shipment.delivery_address = shipment.warehouse.address
......
* Store warehouse locations on shipments
Version 6.6.0 - 2022-10-31
--------------------------
* Bug fixes (see mercurial logs for details)
......
......@@ -183,13 +183,29 @@
| Eval('incoming_moves', [0]) | Eval('inventory_moves', [0])),
},
help="Where the stock is received.")
warehouse_input = fields.Function(fields.Many2One('stock.location',
'Warehouse Input'),
'on_change_with_warehouse_input')
warehouse_storage = fields.Function(fields.Many2One('stock.location',
'Warehouse Storage'),
'on_change_with_warehouse_storage')
warehouse_input = fields.Many2One(
'stock.location', "Warehouse Input", required=True,
domain=[
('type', '=', 'storage'),
If(Eval('state') == 'draft',
('parent', 'child_of', [Eval('warehouse', -1)]),
()),
],
states={
'readonly': Eval('state') != 'draft',
})
warehouse_storage = fields.Many2One(
'stock.location', "Warehouse Storage", required=True,
domain=[
('type', '=', 'storage'),
If(Eval('state') == 'draft',
('parent', 'child_of', [Eval('warehouse', -1)]),
()),
],
states={
'readonly': Eval('state') != 'draft',
})
incoming_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Incoming Moves',
add_remove=[
('shipment', '=', None),
......@@ -192,8 +208,7 @@
incoming_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Incoming Moves',
add_remove=[
('shipment', '=', None),
('from_location', '=', Eval('supplier_location')),
('state', '=', 'draft'),
If(Eval('warehouse_input') == Eval('warehouse_storage'),
('to_location', 'child_of',
......@@ -201,7 +216,9 @@
('to_location', '=', Eval('warehouse_input'))),
],
domain=[
('from_location', '=', Eval('supplier_location')),
If(Eval('state') == 'draft',
('from_location', '=', Eval('supplier_location')),
()),
If(Eval('warehouse_input') == Eval('warehouse_storage'),
('to_location', 'child_of',
[Eval('warehouse_input', -1)], 'parent'),
......@@ -210,7 +227,7 @@
],
states={
'readonly': (
Eval('state').in_(['received', 'done', 'cancelled'])
(Eval('state') != 'draft')
| ~Eval('warehouse') | ~Eval('supplier')),
},
help="The moves that bring the stock into the warehouse."),
......@@ -296,6 +313,8 @@
@classmethod
def __register__(cls, module_name):
pool = Pool()
Location = pool.get('stock.location')
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(module_name)
sql_table = cls.__table__()
......@@ -299,6 +318,7 @@
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(module_name)
sql_table = cls.__table__()
location = Location.__table__()
# Migration from 3.8: rename code into number
if table.column_exist('code'):
......@@ -311,6 +331,20 @@
[sql_table.state], ['cancelled'],
where=sql_table.state == 'cancel'))
# Migration from 6.6: fill warehouse locations
cursor.execute(*sql_table.update(
[sql_table.warehouse_input],
location.select(
location.input_location,
where=location.id == sql_table.warehouse),
where=sql_table.warehouse_input == Null))
cursor.execute(*sql_table.update(
[sql_table.warehouse_storage],
location.select(
location.storage_location,
where=location.id == sql_table.warehouse),
where=sql_table.warehouse_storage == Null))
@classmethod
def order_number(cls, tables):
table, _ = tables[None]
......@@ -334,6 +368,14 @@
Location = Pool().get('stock.location')
return Location.get_default_warehouse()
@fields.depends('warehouse')
def on_change_warehouse(self):
if self.warehouse:
self.warehouse_input = self.warehouse.input_location
self.warehouse_storage = self.warehouse.storage_location
else:
self.warehouse_input = self.warehouse_storage = None
@staticmethod
def default_company():
return Transaction().context.get('company')
......@@ -349,28 +391,6 @@
if self.supplier and self.supplier.supplier_location:
return self.supplier.supplier_location.id
@classmethod
def default_warehouse_input(cls):
warehouse = cls.default_warehouse()
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_input()
@fields.depends('warehouse')
def on_change_with_warehouse_input(self, name=None):
if self.warehouse:
return self.warehouse.input_location.id
@classmethod
def default_warehouse_storage(cls):
warehouse = cls.default_warehouse()
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_storage()
@fields.depends('warehouse')
def on_change_with_warehouse_storage(self, name=None):
if self.warehouse:
return self.warehouse.storage_location.id
def get_incoming_moves(self, name):
moves = []
if self.warehouse_input == self.warehouse_storage:
......@@ -1036,11 +1056,29 @@
| Eval('outgoing_moves', [0]) | Eval('inventory_moves', [0])),
}, domain=[('type', '=', 'warehouse')],
help="Where the stock is sent from.")
warehouse_storage = fields.Function(fields.Many2One('stock.location',
'Warehouse Storage'), 'on_change_with_warehouse_storage')
warehouse_output = fields.Function(fields.Many2One('stock.location',
'Warehouse Output'), 'on_change_with_warehouse_output')
warehouse_storage = fields.Many2One(
'stock.location', "Warehouse Storage", required=True,
domain=[
('type', '=', 'storage'),
If(Eval('state') == 'draft',
('parent', 'child_of', [Eval('warehouse', -1)]),
()),
],
states={
'readonly': Eval('state') != 'draft',
})
warehouse_output = fields.Many2One(
'stock.location', "Warehouse Output", required=True,
domain=[
('type', '=', 'storage'),
If(Eval('state') == 'draft',
('parent', 'child_of', [Eval('warehouse', -1)]),
()),
],
states={
'readonly': Eval('state') != 'draft',
})
outgoing_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Outgoing Moves',
domain=[
('from_location', '=', Eval('warehouse_output')),
......@@ -1043,8 +1081,10 @@
outgoing_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Outgoing Moves',
domain=[
('from_location', '=', Eval('warehouse_output')),
('to_location', '=', Eval('customer_location')),
If(~Eval('state').in_(['done', 'cancelled']),
('to_location', '=', Eval('customer_location')),
()),
('company', '=', Eval('company')),
],
states={
......@@ -1196,6 +1236,8 @@
@classmethod
def __register__(cls, module_name):
pool = Pool()
Location = pool.get('stock.location')
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(module_name)
sql_table = cls.__table__()
......@@ -1199,6 +1241,7 @@
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(module_name)
sql_table = cls.__table__()
location = Location.__table__()
# Migration from 3.8: rename code into number
if table.column_exist('code'):
......@@ -1215,6 +1258,20 @@
[sql_table.state], ['cancelled'],
where=sql_table.state == 'cancel'))
# Migration from 6.6: fill warehouse locations
cursor.execute(*sql_table.update(
[sql_table.warehouse_storage],
location.select(
location.storage_location,
where=location.id == sql_table.warehouse),
where=sql_table.warehouse_storage == Null))
cursor.execute(*sql_table.update(
[sql_table.warehouse_output],
location.select(
location.output_location,
where=location.id == sql_table.warehouse),
where=sql_table.warehouse_output == Null))
@classmethod
def order_number(cls, tables):
table, _ = tables[None]
......@@ -1238,6 +1295,17 @@
def default_company():
return Transaction().context.get('company')
@fields.depends('warehouse')
def on_change_warehouse(self):
if self.warehouse:
if self.warehouse.picking_location:
self.warehouse_storage = self.warehouse.picking_location
else:
self.warehouse_storage = self.warehouse.storage_location
self.warehouse_output = self.warehouse.output_location
else:
self.warehouse_storage = self.warehouse_output = None
@fields.depends('customer', 'warehouse')
def on_change_customer(self):
self.delivery_address = None
......@@ -1252,32 +1320,6 @@
if self.customer:
return self.customer.customer_location.id
@classmethod
def default_warehouse_storage(cls):
warehouse = cls.default_warehouse()
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_storage()
@fields.depends('warehouse')
def on_change_with_warehouse_storage(self, name=None):
if self.warehouse:
if self.warehouse.picking_location:
location = self.warehouse.picking_location
else:
location = self.warehouse.storage_location
return location.id
@classmethod
def default_warehouse_output(cls):
warehouse = cls.default_warehouse()
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_output()
@fields.depends('warehouse')
def on_change_with_warehouse_output(self, name=None):
if self.warehouse:
return self.warehouse.output_location.id
def get_outgoing_moves(self, name):
moves = []
for move in self.moves:
......@@ -1719,10 +1761,28 @@
| Eval('incoming_moves', [0]) | Eval('inventory_moves', [0])),
}, domain=[('type', '=', 'warehouse')],
help="Where the stock is returned.")
warehouse_storage = fields.Function(fields.Many2One('stock.location',
'Warehouse Storage'), 'on_change_with_warehouse_storage')
warehouse_input = fields.Function(fields.Many2One('stock.location',
'Warehouse Input'), 'on_change_with_warehouse_input')
warehouse_storage = fields.Many2One(
'stock.location', "Warehouse Storage", required=True,
domain=[
('type', '=', 'storage'),
If(Eval('state') == 'draft',
('parent', 'child_of', [Eval('warehouse', -1)]),
()),
],
states={
'readonly': Eval('state') != 'draft',
})
warehouse_input = fields.Many2One(
'stock.location', "Warehouse Input", required=True,
domain=[
('type', '=', 'storage'),
If(Eval('state') == 'draft',
('parent', 'child_of', [Eval('warehouse', -1)]),
()),
],
states={
'readonly': Eval('state') != 'draft',
})
incoming_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Incoming Moves',
domain=[
......@@ -1726,7 +1786,9 @@
incoming_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Incoming Moves',
domain=[
('from_location', '=', Eval('customer_location')),
If(Eval('state') == 'draft',
('from_location', '=', Eval('customer_location')),
()),
If(Eval('warehouse_input') == Eval('warehouse_storage'),
('to_location', 'child_of',
[Eval('warehouse_input', -1)], 'parent'),
......@@ -1822,6 +1884,8 @@
@classmethod
def __register__(cls, module_name):
pool = Pool()
Location = pool.get('stock.location')
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(module_name)
sql_table = cls.__table__()
......@@ -1825,6 +1889,7 @@
cursor = Transaction().connection.cursor()
table = cls.__table_handler__(module_name)
sql_table = cls.__table__()
location = Location.__table__()
# Migration from 3.8: rename code into number
if table.column_exist('code'):
......@@ -1843,6 +1908,20 @@
# Migration from 6.4: remove required on contact_address
table.not_null_action('contact_address', 'remove')
# Migration from 6.6: fill warehouse locations
cursor.execute(*sql_table.update(
[sql_table.warehouse_input],
location.select(
location.input_location,
where=location.id == sql_table.warehouse),
where=sql_table.warehouse_input == Null))
cursor.execute(*sql_table.update(
[sql_table.warehouse_storage],
location.select(
location.storage_location,
where=location.id == sql_table.warehouse),
where=sql_table.warehouse_storage == Null))
@classmethod
def order_number(cls, tables):
table, _ = tables[None]
......@@ -1862,6 +1941,14 @@
Location = Pool().get('stock.location')
return Location.get_default_warehouse()
@fields.depends('warehouse')
def on_change_warehouse(self):
if self.warehouse:
self.warehouse_input = self.warehouse.input_location
self.warehouse_storage = self.warehouse.storage_location
else:
self.warehouse_input = self.warehouse_storage = None
@staticmethod
def default_company():
return Transaction().context.get('company')
......@@ -1877,28 +1964,6 @@
if self.customer:
return self.customer.customer_location.id
@classmethod
def default_warehouse_storage(cls):
warehouse = cls.default_warehouse()
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_storage()
@fields.depends('warehouse')
def on_change_with_warehouse_storage(self, name=None):
if self.warehouse:
return self.warehouse.storage_location.id
@classmethod
def default_warehouse_input(cls):
warehouse = cls.default_warehouse()
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_input()
@fields.depends('warehouse')
def on_change_with_warehouse_input(self, name=None):
if self.warehouse:
return self.warehouse.input_location.id
def get_incoming_moves(self, name):
moves = []
if self.warehouse_input == self.warehouse_storage:
......
......@@ -27,6 +27,11 @@
<field name="inventory_moves" colspan="4" view_ids="stock.move_view_list_shipment"/>
</page>
<page string="Other Info" id="other">
<label name="warehouse_input"/>
<field name="warehouse_input"/>
<label name="warehouse_storage"/>
<field name="warehouse_storage"/>
<label name="received_by"/>
<field name="received_by"/>
<label name="done_by"/>
......
......@@ -26,6 +26,11 @@
<field name="outgoing_moves" colspan="4" view_ids="stock.move_view_list_shipment"/>
</page>
<page string="Other Info" id="other">
<label name="warehouse_storage"/>
<field name="warehouse_storage"/>
<label name="warehouse_output"/>
<field name="warehouse_output"/>
<label name="picked_by"/>
<field name="picked_by"/>
<label name="packed_by"/>
......
......@@ -26,6 +26,11 @@
<field name="inventory_moves" colspan="4" view_ids="stock.move_view_list_shipment"/>
</page>
<page string="Other Info" id="other">
<label name="warehouse_input"/>
<field name="warehouse_input"/>
<label name="warehouse_storage"/>
<field name="warehouse_storage"/>
<label name="received_by"/>
<field name="received_by"/>
<label name="done_by"/>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment