diff --git a/addons/mrp/views/mrp_production_views.xml b/addons/mrp/views/mrp_production_views.xml
index 2fa32e3769b..3d5e9a2c4a3 100644
--- a/addons/mrp/views/mrp_production_views.xml
+++ b/addons/mrp/views/mrp_production_views.xml
@@ -115,6 +115,7 @@
diff --git a/addons/purchase_stock/models/purchase.py b/addons/purchase_stock/models/purchase.py
index c5a74770b80..d07893425ed 100644
--- a/addons/purchase_stock/models/purchase.py
+++ b/addons/purchase_stock/models/purchase.py
@@ -239,6 +239,7 @@ class PurchaseOrderLine(models.Model):
orderpoint_id = fields.Many2one('stock.warehouse.orderpoint', 'Orderpoint')
move_dest_ids = fields.One2many('stock.move', 'created_purchase_line_id', 'Downstream Moves')
delay_alert = fields.Boolean(string='Delay alert')
+ product_description_variants = fields.Char('Custom Description')
propagate_date = fields.Boolean(string="Propagate Rescheduling", help='The rescheduling is propagated to the next move.')
propagate_date_minimum_delta = fields.Integer(string='Reschedule if Higher Than', help='The change must be higher than this value to be propagated')
propagate_cancel = fields.Boolean('Propagate cancellation', default=True)
@@ -381,12 +382,14 @@ class PurchaseOrderLine(models.Model):
def _prepare_stock_move_vals(self, picking, price_unit, product_uom_qty, product_uom):
self.ensure_one()
+ description_picking = self.product_id._get_description(self.order_id.picking_type_id)
+ if self.product_description_variants:
+ description_picking += self.product_description_variants
return {
# truncate to 2000 to avoid triggering index limit error
# TODO: remove index in master?
'name': (self.name or '')[:2000],
'product_id': self.product_id.id,
- 'product_uom': self.product_uom.id,
'date': self.order_id.date_order,
'date_expected': self.date_planned,
'location_id': self.order_id.partner_id.property_stock_supplier.id,
@@ -403,7 +406,7 @@ class PurchaseOrderLine(models.Model):
'origin': self.order_id.name,
'propagate_date': self.propagate_date,
'propagate_date_minimum_delta': self.propagate_date_minimum_delta,
- 'description_picking': self.product_id._get_description(self.order_id.picking_type_id),
+ 'description_picking': description_picking,
'propagate_cancel': self.propagate_cancel,
'delay_alert': self.delay_alert,
'route_ids': self.order_id.picking_type_id.warehouse_id and [(6, 0, [x.id for x in self.order_id.picking_type_id.warehouse_id.route_ids])] or [],
@@ -414,14 +417,19 @@ class PurchaseOrderLine(models.Model):
@api.model
def _prepare_purchase_order_line_from_procurement(self, product_id, product_qty, product_uom, company_id, values, po):
+ line_description = product_id._get_description(po.picking_type_id)
+ if values.get('product_description_variants'):
+ line_description += values['product_description_variants']
supplier = values.get('supplier')
res = self._prepare_purchase_order_line(product_id, product_qty, product_uom, company_id, supplier, po)
+ res['name'] = line_description
res['move_dest_ids'] = [(4, x.id) for x in values.get('move_dest_ids', [])]
res['orderpoint_id'] = values.get('orderpoint_id', False) and values.get('orderpoint_id').id
res['propagate_cancel'] = values.get('propagate_cancel')
res['delay_alert'] = values.get('delay_alert')
res['propagate_date'] = values.get('propagate_date')
res['propagate_date_minimum_delta'] = values.get('propagate_date_minimum_delta')
+ res['product_description_variants'] = values.get('product_description_variants')
return res
def _create_stock_moves(self, picking):
@@ -442,9 +450,13 @@ class PurchaseOrderLine(models.Model):
args can be merged. If it returns an empty record then a new line will
be created.
"""
+ description_picking = product_id._get_description(self.order_id.picking_type_id) or ''
+ if values.get('product_description_variants'):
+ description_picking += values['product_description_variants']
lines = self.filtered(
lambda l: l.propagate_date == values['propagate_date'] and
l.propagate_date_minimum_delta == values['propagate_date_minimum_delta'] and
l.propagate_cancel == values['propagate_cancel'] and
- ((values['orderpoint_id'] and not values['move_dest_ids']) and l.orderpoint_id == values['orderpoint_id'] or True))
+ ((values['orderpoint_id'] and not values['move_dest_ids']) and l.orderpoint_id == values['orderpoint_id'] or True) and
+ (values.get('product_description_variants') and l.name == description_picking or True))
return lines and lines[0] or self.env['purchase.order.line']
diff --git a/addons/purchase_stock/models/stock_rule.py b/addons/purchase_stock/models/stock_rule.py
index 0df54976cee..a102726dece 100644
--- a/addons/purchase_stock/models/stock_rule.py
+++ b/addons/purchase_stock/models/stock_rule.py
@@ -159,12 +159,14 @@ class StockRule(models.Model):
# necessary anymore since those values are taken from destination moves.
return procurement.product_id, procurement.product_uom, procurement.values['propagate_date'],\
procurement.values['propagate_date_minimum_delta'], procurement.values['propagate_cancel'],\
+ procurement.values.get('product_description_variants'),\
(procurement.values.get('orderpoint_id') and not procurement.values.get('move_dest_ids')) and procurement.values['orderpoint_id']
@api.model
def _get_procurements_to_merge_sorted(self, procurement):
return procurement.product_id.id, procurement.product_uom.id, procurement.values['propagate_date'],\
procurement.values['propagate_date_minimum_delta'], procurement.values['propagate_cancel'],\
+ procurement.values.get('product_description_variants'),\
(procurement.values.get('orderpoint_id') and not procurement.values.get('move_dest_ids')) and procurement.values['orderpoint_id']
@api.model
diff --git a/addons/purchase_stock/tests/common.py b/addons/purchase_stock/tests/common.py
index 99917378ff1..feada30badc 100644
--- a/addons/purchase_stock/tests/common.py
+++ b/addons/purchase_stock/tests/common.py
@@ -35,6 +35,12 @@ class PurchaseTestCommon(TestStockCommon):
'route_ids': [(6, 0, [cls.route_buy, cls.route_mto])],
'seller_ids': [(0, 0, {'name': cls.partner_1.id, 'delay': 5})]})
+ cls.t_shirt = cls.env['product.product'].create({
+ 'name': 'T-shirt',
+ 'route_ids': [(6, 0, [cls.route_buy, cls.route_mto])],
+ 'seller_ids': [(0, 0, {'name': cls.partner_1.id, 'delay': 5})]
+ })
+
# Update product_2 with type, route and Delivery Lead Time
cls.product_2.write({
'type': 'product',
diff --git a/addons/purchase_stock/tests/test_purchase_lead_time.py b/addons/purchase_stock/tests/test_purchase_lead_time.py
index 45d29ce71f2..2706527dd78 100644
--- a/addons/purchase_stock/tests/test_purchase_lead_time.py
+++ b/addons/purchase_stock/tests/test_purchase_lead_time.py
@@ -242,6 +242,57 @@ class TestPurchaseLeadTime(PurchaseTestCommon):
self.assertEqual(po_line[0].product_qty, 10, 'the purchase order line has a wrong quantity')
self.assertEqual(po_line[1].product_qty, 5, 'the purchase order line has a wrong quantity')
+ def test_merge_po_line_3(self):
+ """Chage merging po line if same procurement is done depending on
+ propagate_date, propagate_date_minimum_delta and custom values.
+ """
+ # Create procurement order of product_1
+ ProcurementGroup = self.env['procurement.group']
+ procurement_values = {
+ 'warehouse_id': self.warehouse_1,
+ 'rule_id': self.warehouse_1.buy_pull_id,
+ 'date_planned': fields.Datetime.to_string(fields.datetime.now() + timedelta(days=10)),
+ 'group_id': False,
+ 'route_ids': [],
+ }
+
+ procurement_values['product_description_variants'] = '[{"color": "Red"}]'
+ procurement_values['description'] = "T-shirt (Red)"
+ order_1_values = procurement_values
+ ProcurementGroup.run([self.env['procurement.group'].Procurement(
+ self.t_shirt, 5, self.uom_unit, self.warehouse_1.lot_stock_id,
+ self.t_shirt.name, '/', self.env.company, order_1_values)
+ ])
+ purchase_order = self.env['purchase.order.line'].search([('product_id', '=', self.t_shirt.id)], limit=1).order_id
+ self.assertEqual(len(purchase_order.order_line), 1, 'wrong number of order line is created')
+
+ procurement_values['product_description_variants'] = '[{"color": "Red"}]'
+ order_2_values = procurement_values
+ ProcurementGroup.run([self.env['procurement.group'].Procurement(
+ self.t_shirt, 10, self.uom_unit, self.warehouse_1.lot_stock_id,
+ self.t_shirt.name, '/', self.env.company, order_2_values)
+ ])
+ self.env['procurement.group'].run_scheduler()
+ self.assertEqual(len(purchase_order.order_line), 1, 'line with same custom value should be merged')
+ self.assertEqual(purchase_order.order_line[0].product_qty, 15, 'line with same custom value should be merged and qty should be update')
+
+ procurement_values['product_description_variants'] = '[{"color": "Green"}]'
+ procurement_values['description'] = "T-shirt (Green)"
+
+ order_3_values = procurement_values
+ ProcurementGroup.run([self.env['procurement.group'].Procurement(
+ self.t_shirt, 10, self.uom_unit, self.warehouse_1.lot_stock_id,
+ self.t_shirt.name, '/', self.env.company, order_3_values)
+ ])
+ self.assertEqual(len(purchase_order.order_line), 2, 'line with different custom value should not be merged')
+ self.assertEqual(purchase_order.order_line.filtered(lambda x: x.product_qty == 15).name, "T-shirt (Red)", 'wrong description in po lines')
+ self.assertEqual(purchase_order.order_line.filtered(lambda x: x.product_qty == 10).name, "T-shirt (Green)", 'wrong description in po lines')
+
+ purchase_order.button_confirm()
+
+ self.assertEqual(purchase_order.picking_ids[0].move_ids_without_package.filtered(lambda x: x.product_uom_qty == 15).description_picking, "T-shirt (Red)", 'wrong description in picking')
+ self.assertEqual(purchase_order.picking_ids[0].move_ids_without_package.filtered(lambda x: x.product_uom_qty == 10).description_picking, "T-shirt (Green)", 'wrong description in picking')
+
def test_reordering_days_to_purchase(self):
self.patcher = patch('odoo.addons.stock.models.stock_orderpoint.fields.Date', wraps=fields.Date)
self.mock_date = self.patcher.start()
diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py
index 12f2d445689..8833634c315 100644
--- a/addons/sale_stock/models/sale_order.py
+++ b/addons/sale_stock/models/sale_order.py
@@ -445,6 +445,7 @@ class SaleOrderLine(models.Model):
'route_ids': self.route_id,
'warehouse_id': self.order_id.warehouse_id or False,
'partner_id': self.order_id.partner_shipping_id.id,
+ 'product_description_variants': self._get_sale_order_line_multiline_description_variants(),
'company_id': self.order_id.company_id,
})
for line in self.filtered("order_id.commitment_date"):
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index f322bb7ea6e..5540fdcaf51 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -691,7 +691,7 @@ class StockMove(models.Model):
'product_id', 'price_unit', 'procure_method', 'location_id', 'location_dest_id',
'product_uom', 'restrict_partner_id', 'scrapped', 'origin_returned_move_id',
'package_level_id', 'propagate_cancel', 'propagate_date', 'propagate_date_minimum_delta',
- 'delay_alert',
+ 'delay_alert', 'description_picking'
]
@api.model
@@ -701,7 +701,7 @@ class StockMove(models.Model):
move.product_id.id, move.price_unit, move.procure_method, move.location_id, move.location_dest_id,
move.product_uom.id, move.restrict_partner_id.id, move.scrapped, move.origin_returned_move_id.id,
move.package_level_id.id, move.propagate_cancel, move.propagate_date, move.propagate_date_minimum_delta,
- move.delay_alert,
+ move.delay_alert, move.description_picking
]
def _clean_merged(self):
@@ -1040,6 +1040,7 @@ class StockMove(models.Model):
elif self.rule_id.group_propagation_option == 'none':
group_id = False
return {
+ 'product_description_variants': self.description_picking and self.description_picking.replace(self.product_id._get_description(self.picking_type_id), ''),
'date_planned': self.date_expected,
'move_dest_ids': self,
'group_id': group_id,
diff --git a/addons/stock/models/stock_rule.py b/addons/stock/models/stock_rule.py
index 7570c0cbfb0..ddc37eccbcf 100644
--- a/addons/stock/models/stock_rule.py
+++ b/addons/stock/models/stock_rule.py
@@ -285,6 +285,9 @@ class StockRule(models.Model):
date_expected = fields.Datetime.to_string(
fields.Datetime.from_string(values['date_planned']) - relativedelta(days=self.delay or 0)
)
+ picking_description = product_id._get_description(self.picking_type_id)
+ if values.get('product_description_variants'):
+ picking_description += values['product_description_variants']
# it is possible that we've already got some move done, so check for the done qty and create
# a new move with the correct qty
qty_left = product_qty
@@ -315,7 +318,7 @@ class StockRule(models.Model):
'propagate_cancel': self.propagate_cancel,
'propagate_date': self.propagate_date,
'propagate_date_minimum_delta': self.propagate_date_minimum_delta,
- 'description_picking': product_id._get_description(self.picking_type_id),
+ 'description_picking': picking_description,
'priority': values.get('priority', "1"),
'delay_alert': self.delay_alert,
'orderpoint_id': values.get('orderpoint_id') and values['orderpoint_id'].id,