summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorsvs-odoo <svs@odoo.com>2019-06-13 11:34:05 +0000
committersvs-odoo <svs@odoo.com>2019-08-14 08:44:52 +0000
commit2a2c27fa45d2a9859cf3714dc5c7d66cf0022e33 (patch)
tree437d9be753482cd7046125e2748290945c79edec /addons
parent629e8da14fdeae534ab08b86f2cfed63901a61e2 (diff)
[IMP] mrp, sale_mrp: planned date on MO
The purpose of this commit is to simplify the `mrp.production` model in reducing the number of date field. The following fields was kept: - `date_planned_start`: the planned date for the beginning of the MO - `date_planned_finished`: the planned date for the ending of the MO - `date_start_wo`: the preferred date to start a Work Order in case the MO will plan one. - `date_deadline`: is only indicative and is automatically set when the manufacturing order is needed for a sale order. - `date_start` and `date_finished`: no changes. Task #1935229 Co-authored-by: Whenrow <whe@odoo.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/mrp/models/mrp_production.py61
-rw-r--r--addons/mrp/models/mrp_workorder.py20
-rw-r--r--addons/mrp/models/stock_rule.py2
-rw-r--r--addons/mrp/tests/test_workorder_operation.py7
-rw-r--r--addons/mrp/views/mrp_production_views.xml84
-rw-r--r--addons/sale_mrp/tests/test_sale_mrp_lead_time.py8
6 files changed, 125 insertions, 57 deletions
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index 465cf23398d..ff757d69e5e 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -51,6 +51,12 @@ class MrpProduction(models.Model):
location = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1).lot_stock_id
return location and location.id or False
+ @api.model
+ def _get_default_date_planned_finished(self):
+ if self.env.context.get('default_date_planned_start'):
+ return fields.Datetime.to_datetime(self.env.context.get('default_date_planned_start')) + datetime.timedelta(hours=1)
+ return datetime.datetime.now() + datetime.timedelta(hours=1)
+
name = fields.Char(
'Reference', copy=False, readonly=True, default=lambda x: _('New'))
origin = fields.Char(
@@ -89,28 +95,24 @@ class MrpProduction(models.Model):
states={'draft': [('readonly', False)]},
help="Location where the system will stock the finished products.")
date_planned_start = fields.Datetime(
- 'Deadline Start', copy=False, default=fields.Datetime.now,
- index=True, required=True,
- states={'draft': [('readonly', False)]})
+ 'Planned Date', copy=False, default=fields.Datetime.now,
+ help="Date at which you plan to start the production.",
+ index=True, required=True, store=True)
date_planned_finished = fields.Datetime(
- 'Deadline End', copy=False, default=fields.Datetime.now,
- index=True,
- states={'draft': [('readonly', False)]})
- date_planned_start_wo = fields.Datetime(
- 'Scheduled Start Date', compute='_compute_date_planned',
- copy=False, store=True,
- states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
- date_planned_finished_wo = fields.Datetime(
- 'Scheduled End Date', compute='_compute_date_planned',
- copy=False, store=True,
- states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
+ 'Planned End Date',
+ default=_get_default_date_planned_finished,
+ help="Date at which you plan to finish the production.",
+ copy=False, store=True)
+ date_deadline = fields.Datetime(
+ 'Deadline', copy=False, index=True,
+ help="Informative date allowing to define when the manufacturing order should be processed at the latest to fulfill delivery on time.")
date_start = fields.Datetime('Start Date', copy=False, index=True, readonly=True)
date_finished = fields.Datetime('End Date', copy=False, index=True, readonly=True)
date_start_wo = fields.Datetime(
- 'Planned Start Date', copy=False, readonly=True,
- states={'draft': [('readonly', False)], 'confirmed': [('readonly', False)]},
- help="The work orders will be planned based on the availability of the work centers starting from "
- "this date. If emtpy, the work orders are planned as soon as possible.")
+ 'Plan From', copy=False, readonly=True,
+ help="Work orders will be planned based on the availability of the work centers\
+ starting from this date. If empty, the work orders will be planned as soon as possible.",
+ )
bom_id = fields.Many2one(
'mrp.bom', 'Bill of Material',
readonly=True, states={'draft': [('readonly', False)]},
@@ -370,18 +372,6 @@ class MrpProduction(models.Model):
for production in self:
production.scrap_count = count_data.get(production.id, 0)
- @api.depends('workorder_ids.date_planned_start', 'workorder_ids.date_planned_finished')
- def _compute_date_planned(self):
- for order in self:
- date_planned_start_wo = date_planned_finished_wo = False
- if order.workorder_ids:
- start_dates = order.workorder_ids.filtered(lambda r: r.date_planned_start is not False).sorted(key=lambda r: r.date_planned_start)
- date_planned_start_wo = start_dates[0].date_planned_start if start_dates else False
- finished_dates = order.workorder_ids.filtered(lambda r: r.date_planned_finished is not False).sorted(key=lambda r: r.date_planned_finished)
- date_planned_finished_wo = finished_dates[-1].date_planned_finished if finished_dates else False
- order.date_planned_start_wo = date_planned_start_wo
- order.date_planned_finished_wo = date_planned_finished_wo
-
_sql_constraints = [
('name_uniq', 'unique(name, company_id)', 'Reference must be unique per Company!'),
('qty_positive', 'check (product_qty > 0)', 'The quantity to produce must be positive!'),
@@ -414,6 +404,8 @@ class MrpProduction(models.Model):
'date': self.date_planned_start,
'date_expected': self.date_planned_start,
})
+ if not self.routing_id:
+ self.date_planned_finished = self.date_planned_start + datetime.timedelta(hours=1)
@api.onchange('bom_id', 'product_id', 'product_qty', 'product_uom_id')
def _onchange_move_raw(self):
@@ -451,6 +443,11 @@ class MrpProduction(models.Model):
'date_expected': vals['date_planned_start'],
})
for production in self:
+ if 'date_planned_start' in vals:
+ if production.state in ['done', 'cancel']:
+ raise UserError(_('You cannot move a manufacturing order once it is cancelled or done.'))
+ if production.workorder_ids and not self.env.context.get('force_date', False):
+ raise UserError(_('You cannot move a planned manufacturing order.'))
if 'move_raw_ids' in vals and production.state != 'draft':
production.move_raw_ids.filtered(lambda m: m.state == 'draft')._action_confirm()
return res
@@ -715,6 +712,10 @@ class MrpProduction(models.Model):
})
vals['leave_id'] = leave.id
workorder.write(vals)
+ self.with_context(force_date=True).write({
+ 'date_planned_start': self.workorder_ids[0].date_planned_start,
+ 'date_planned_finished': self.workorder_ids[-1].date_planned_finished
+ })
def button_unplan(self):
if any(wo.state == 'done' for wo in self.workorder_ids):
diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py
index f7be61d8325..2fd03cc7654 100644
--- a/addons/mrp/models/mrp_workorder.py
+++ b/addons/mrp/models/mrp_workorder.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from datetime import datetime
+from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from collections import defaultdict
@@ -146,6 +146,14 @@ class MrpWorkorder(models.Model):
'date_to': date_to,
})
+ @api.onchange('date_planned_start')
+ def _onchange_date_planned_start(self):
+ if self.duration_expected:
+ time_delta = timedelta(minutes=self.duration_expected)
+ else:
+ time_delta = timedelta(hours=1)
+ self.update({'date_planned_finished': self.date_planned_start + time_delta})
+
@api.onchange('finished_lot_id')
def _onchange_finished_lot_id(self):
"""When the user changes the lot being currently produced, suggest
@@ -256,6 +264,16 @@ class MrpWorkorder(models.Model):
end_date = fields.Datetime.to_datetime(values.get('date_planned_finished')) or workorder.date_planned_finished
if start_date and end_date and start_date > end_date:
raise UserError(_('The planned end date of the work order cannot be prior to the planned start date, please correct this to save the work order.'))
+ # Update MO dates if the start date of the first WO or the
+ # finished date of the last WO is update.
+ if workorder == workorder.production_id.workorder_ids[0] and 'date_planned_start' in values:
+ workorder.production_id.with_context(force_date=True).write({
+ 'date_planned_start': values['date_planned_start']
+ })
+ if workorder == workorder.production_id.workorder_ids[-1] and 'date_planned_finished' in values:
+ workorder.production_id.with_context(force_date=True).write({
+ 'date_planned_finished': values['date_planned_finished']
+ })
return super(MrpWorkorder, self).write(values)
def _generate_wo_lines(self):
diff --git a/addons/mrp/models/stock_rule.py b/addons/mrp/models/stock_rule.py
index 5e7e9d1bf81..ff840682e1d 100644
--- a/addons/mrp/models/stock_rule.py
+++ b/addons/mrp/models/stock_rule.py
@@ -82,7 +82,7 @@ class StockRule(models.Model):
'location_src_id': self.location_src_id.id or self.picking_type_id.default_location_src_id.id or location_id.id,
'location_dest_id': location_id.id,
'bom_id': bom.id,
- 'date_planned_start': fields.Datetime.to_string(self._get_date_planned(product_id, company_id, values)),
+ 'date_deadline': fields.Datetime.to_string(self._get_date_planned(product_id, company_id, values)),
'date_planned_finished': values['date_planned'],
'procurement_group_id': False,
'propagate_cancel': self.propagate_cancel,
diff --git a/addons/mrp/tests/test_workorder_operation.py b/addons/mrp/tests/test_workorder_operation.py
index 0c711d85302..d4a1f84076d 100644
--- a/addons/mrp/tests/test_workorder_operation.py
+++ b/addons/mrp/tests/test_workorder_operation.py
@@ -908,6 +908,7 @@ class TestWorkOrderProcess(TestMrpCommon):
- calendar wc1 :[mo1][mo4]
- calendar wc2 :[mo2 ][mo5 ]
- calendar wc3 :[mo3 ][mo6 ]"""
+ planned_date = datetime(2019, 5, 13, 9, 0)
self.workcenter_1.alternative_workcenter_ids = self.wc_alt_1 | self.wc_alt_2
workcenters = [self.wc_alt_2, self.wc_alt_1, self.workcenter_1]
for i in range(3):
@@ -916,11 +917,14 @@ class TestWorkOrderProcess(TestMrpCommon):
mo_form.product_id = self.product_4
mo_form.bom_id = self.planning_bom
mo_form.product_qty = 1
+ mo_form.date_start_wo = planned_date
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
# Check that workcenters change
self.assertEqual(mo.workorder_ids.workcenter_id, workcenters[i], "wrong workcenter %d" % i)
+ self.assertAlmostEqual(mo.date_planned_start, planned_date, delta=timedelta(seconds=10))
+ self.assertAlmostEqual(mo.date_planned_start, mo.workorder_ids.date_planned_start, delta=timedelta(seconds=10))
for i in range(3):
# Planning 3 more should choose workcenters in opposite order as
@@ -931,11 +935,14 @@ class TestWorkOrderProcess(TestMrpCommon):
mo_form.product_id = self.product_4
mo_form.bom_id = self.planning_bom
mo_form.product_qty = 1
+ mo_form.date_start_wo = planned_date
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
# Check that workcenters change
self.assertEqual(mo.workorder_ids.workcenter_id, workcenters[i], "wrong workcenter %d" % i)
+ self.assertNotEqual(mo.date_planned_start, planned_date)
+ self.assertAlmostEqual(mo.date_planned_start, mo.workorder_ids.date_planned_start, delta=timedelta(seconds=10))
def test_planning_2(self):
""" Plan some manufacturing orders with 2 workorders each
diff --git a/addons/mrp/views/mrp_production_views.xml b/addons/mrp/views/mrp_production_views.xml
index 8be9bcbe634..2bf94654de2 100644
--- a/addons/mrp/views/mrp_production_views.xml
+++ b/addons/mrp/views/mrp_production_views.xml
@@ -9,7 +9,6 @@
<tree decoration-bf="message_needaction==True" default_order="date_planned_start desc" decoration-info="state=='confirmed'" decoration-danger="date_planned_start&lt;current_date and state not in ('done','cancel')" decoration-muted="state in ('done','cancel')" string="Manufacturing Orders">
<field name="message_needaction" invisible="1"/>
<field name="name"/>
- <field name="date_start_wo" optional="hide"/>
<field name="date_planned_start" optional="show"/>
<field name="product_id" optional="show"/>
<field name="product_qty" sum="Total Qty" string="Quantity" optional="show"/>
@@ -46,15 +45,15 @@
<button name="button_mark_done" attrs="{'invisible': [('state', '!=', 'to_close')]}" string="Mark as Done" type="object" class="oe_highlight"/>
<button name="action_confirm" attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('is_locked', '=', False)]}" string="Mark as Todo" type="object" class="oe_highlight"/>
<button name="action_assign" attrs="{'invisible': ['|', '|', ('is_locked', '=', False), ('state', 'in', ('draft', 'done', 'cancel')), ('reservation_state', '=', 'assigned')]}" string="Check availability" type="object" class="oe_highlight"/>
- <button name="button_plan" attrs="{'invisible': ['|', ('state', 'not in', ('confirmed', 'planned')), '|', ('routing_id', '=', False), '|', ('date_planned_start_wo', '!=', False), ('date_planned_finished_wo', '!=', False)]}" type="object" string="Plan" class="oe_highlight"/>
- <button name="button_unplan" type="object" string="Unplan" attrs="{'invisible': ['|', '|', ('state', '!=', 'planned'), ('date_planned_start_wo', '=', False), ('date_planned_finished_wo', '=', False)]}"/>
+ <button name="button_plan" attrs="{'invisible': ['|', ('state', '!=', 'confirmed'), ('routing_id', '=', False)]}" type="object" string="Plan" class="oe_highlight"/>
+ <button name="button_unplan" type="object" string="Unplan" attrs="{'invisible': ['|', '|', ('state', '!=', 'planned'), ('date_planned_start', '=', False), ('date_planned_finished', '=', False)]}"/>
<button name="open_produce_product" attrs="{'invisible': ['|', '|', '|', ('state', '=', 'to_close'), ('is_locked', '=', False), ('reservation_state', '!=', 'assigned'), ('routing_id', '!=', False)]}" string="Produce" type="object" class="oe_highlight"/>
<button name="open_produce_product" attrs="{'invisible': ['|', '|', '|', ('state', '=', 'to_close'), ('is_locked', '=', False), ('reservation_state', 'not in', ('confirmed', 'waiting')), ('routing_id', '!=', False)]}" string="Produce" type="object"/>
<button name="post_inventory" string="Post Inventory" type="object" attrs="{'invisible': [('post_visible', '=', False)]}" groups="base.group_no_one"/>
<button name="action_cancel" type="object" string="Cancel"
- attrs="{'invisible': ['|', '|', ('is_locked', '=', False), ('state', 'in', ('done','cancel')), ('confirm_cancel', '=', True)]}"/>
+ attrs="{'invisible': ['|', '|', '|', ('id', '=', False), ('is_locked', '=', False), ('state', 'in', ('done','cancel')), ('confirm_cancel', '=', True)]}"/>
<button name="action_cancel" type="object" string="Cancel"
- attrs="{'invisible': ['|', '|', ('is_locked', '=', False), ('state', 'in', ('done','cancel')), ('confirm_cancel', '=', False)]}"
+ attrs="{'invisible': ['|', '|', '|', ('id', '=', False), ('is_locked', '=', False), ('state', 'in', ('done','cancel')), ('confirm_cancel', '=', False)]}"
confirm="Some product moves have already been confirmed, this manufacturing order can't be completely cancelled. Are you still sure you want to process ?"/>
<button name="button_scrap" type="object" string="Scrap" attrs="{'invisible': ['|', ('state', 'in', ('cancel', 'draft')), ('is_locked', '=', False)]}"/>
<button name="button_unreserve" type="object" string="Unreserve" attrs="{'invisible': [('unreserve_visible', '=', False)]}"/>
@@ -114,14 +113,56 @@
<field name="routing_id" groups="mrp.group_mrp_routings"/>
</group>
<group>
- <field name="date_planned_start"/>
- <field name="date_planned_finished" invisible="1"/>
- <field name="date_start_wo" attrs="{'invisible': ['|', ('routing_id', '=', False), ('state', 'not in', ['draft', 'confirmed'])]}"/>
- <label for="date_planned_start_wo" string="Scheduled Date" attrs="{'invisible': [('date_planned_start_wo', '=', False)]}"/>
- <div class="o_row" attrs="{'invisible': [('date_planned_start_wo', '=', False)]}">
- <field name="date_planned_start_wo" attrs="{'readonly': [('move_raw_ids', '!=', [])]}"/>
- <label for="date_planned_finished_wo" string="to" attrs="{'invisible': [('date_planned_finished_wo', '=', False)]}"/>
- <field name="date_planned_finished_wo" attrs="{'readonly': [('move_raw_ids', '!=', [])]}"/>
+ <field name="date_deadline" attrs="{'readonly': [('state', 'in', ['done', 'cancel'])]}"/>
+ <field name="date_start_wo"
+ attrs="{'invisible': [
+ '|',
+ '&amp;',
+ ('routing_id', '!=', False),
+ ('state', 'not in', ['draft', 'confirmed']),
+ ('routing_id', '=', False),
+ ], 'readonly': [
+ ('routing_id', '!=', False),
+ ('state', 'not in', ['draft', 'confirmed']),
+ ]}"/>
+ <div class="o_row o_td_label">
+ <label for="date_planned_start" string="Planned Date"
+ attrs="{'invisible': [
+ ('routing_id', '!=', False),
+ ('state', 'in', ['draft', 'confirmed'])
+ ]}"/>
+ </div>
+ <div class="o_row">
+ <field name="date_planned_start"
+ attrs="{'invisible': [
+ ('routing_id', '!=', False),
+ ('state', 'in', ['draft', 'confirmed']),
+ ], 'readonly': [
+ '|',
+ '&amp;',
+ ('routing_id', '=', False),
+ ('state', 'in', ['done', 'cancel']),
+ '&amp;',
+ ('routing_id', '!=', False),
+ ('state', 'not in', ['draft', 'confirmed'])]}"/>
+ <label for="date_planned_finished" string="to" attrs="{'invisible': [
+ '|',
+ ('id', '=', False),
+ '&amp;',
+ ('routing_id', '!=', False),
+ ('state', 'in', ['draft', 'confirmed'])
+ ]}"/>
+ <field name="date_planned_finished" required="1"
+ attrs="{'readonly': [
+ '|',
+ '&amp;',
+ ('routing_id', '=', False),
+ ('state', 'in', ['done', 'cancel']),
+ ('routing_id', '!=', False)
+ ], 'invisible': [
+ ('routing_id', '!=', False),
+ ('state', 'in', ['draft', 'confirmed'])
+ ]}"/>
</div>
<field name="user_id"/>
<field name="origin"/>
@@ -204,8 +245,8 @@
<field name="name"/>
<field name="product_id"/>
<field name="product_qty"/>
- <field name="product_uom_id" options="{'no_open':True,'no_create':True}"/>
- <field name="date_planned_start"/>
+ <field name="product_uom_id" options="{'no_open':True,'no_create':True}"/>
+ <field name="date_deadline"/>
<field name="state"/>
<field name="activity_state"/>
<progressbar field="activity_state" colors='{"planned": "success", "today": "warning", "overdue": "danger"}'/>
@@ -220,7 +261,7 @@
</div>
<div class="o_kanban_record_bottom">
<div class="oe_kanban_bottom_left text-muted">
- <span><t t-esc="record.name.value"/> <t t-esc="record.date_planned_start.value and record.date_planned_start.value.split(' ')[0] or False"/></span>
+ <span><t t-esc="record.name.value"/> <t t-esc="record.date_deadline.value and record.date_deadline.value.split(' ')[0] or False"/></span>
<field name="activity_ids" widget="kanban_activity"/>
</div>
<div class="oe_kanban_bottom_right">
@@ -238,7 +279,8 @@
<field name="model">mrp.production</field>
<field eval="2" name="priority"/>
<field name="arch" type="xml">
- <calendar date_start="date_planned_start" string="Manufacturing Orders" color="routing_id" event_limit="5">
+ <calendar date_start="date_planned_start" date_stop="date_planned_finished"
+ string="Manufacturing Orders" color="routing_id" event_limit="5">
<field name="routing_id"/>
<field name="user_id" avatar_field="image_small"/>
<field name="product_id"/>
@@ -259,7 +301,7 @@
<field name="model">mrp.production</field>
<field name="arch" type="xml">
<pivot string="Manufacturing Orders">
- <field name="date_planned_start" type="row"/>
+ <field name="date_deadline" type="row"/>
</pivot>
</field>
</record>
@@ -268,7 +310,7 @@
<field name="model">mrp.production</field>
<field name="arch" type="xml">
<graph string="Manufacturing Orders">
- <field name="date_planned_start"/>
+ <field name="date_deadline"/>
</graph>
</field>
</record>
@@ -292,7 +334,7 @@
<filter string="Waiting for Material" name="waiting" domain="[('reservation_state', 'in', ('waiting', 'confirmed'))]"/>
<filter string="Material Available" name="filter_ready" domain="[('reservation_state', '=', 'assigned')]"/>
<separator/>
- <filter string="Late" domain="['&amp;', ('date_planned_start', '&lt;', current_date), ('state', '=', 'confirmed')]"
+ <filter string="Late" domain="['&amp;', ('date_deadline', '&lt;', current_date), ('state', '=', 'confirmed')]"
name="late" help="Production started late"/>
<separator/>
<field name="product_id"/>
@@ -312,7 +354,7 @@
<group expand="0" string="Group By...">
<filter string="Product" name="product" domain="[]" context="{'group_by':'product_id'}"/>
<filter string="Routing" name="routing" domain="[]" context="{'group_by':'routing_id'}" groups="mrp.group_mrp_routings"/>
- <filter string="Scheduled Date" name="scheduled_date" domain="[]" context="{'group_by':'date_planned_start'}" help="Scheduled Date by Month"/>
+ <filter string="Scheduled Date" name="scheduled_date" domain="[]" context="{'group_by':'date_deadline'}" help="Scheduled Date by Month"/>
<filter string="Status" name="status" domain="[]" context="{'group_by': 'state'}"/>
<filter string="Material Availability" name="groupby_reservation_state" domain="[]" context="{'group_by': 'reservation_state'}"/>
</group>
diff --git a/addons/sale_mrp/tests/test_sale_mrp_lead_time.py b/addons/sale_mrp/tests/test_sale_mrp_lead_time.py
index 0f5acd55daf..b019fc0e708 100644
--- a/addons/sale_mrp/tests/test_sale_mrp_lead_time.py
+++ b/addons/sale_mrp/tests/test_sale_mrp_lead_time.py
@@ -71,9 +71,9 @@ class TestSaleMrpLeadTime(TestStockCommon):
# Check schedule date of manufacturing order
mo_date = out_date - timedelta(days=self.product_1.produce_delay) - timedelta(days=company.manufacturing_lead)
- date_planned_start = fields.Datetime.from_string(manufacturing_order.date_planned_start)
+ date_deadline = fields.Datetime.from_string(manufacturing_order.date_deadline)
self.assertAlmostEqual(
- date_planned_start, mo_date,
+ date_deadline, mo_date,
delta=timedelta(seconds=1),
msg="Schedule date of manufacturing order should be equal to: Schedule date of picking - product's Manufacturing Lead Time - company's Manufacturing Lead Time."
)
@@ -141,9 +141,9 @@ class TestSaleMrpLeadTime(TestStockCommon):
# Check schedule date of manufacturing order
mo_date = pack_date - timedelta(days=self.product_1.produce_delay)
- date_planned_start = fields.Datetime.from_string(manufacturing_order.date_planned_start)
+ date_deadline = fields.Datetime.from_string(manufacturing_order.date_deadline)
self.assertAlmostEqual(
- date_planned_start, mo_date,
+ date_deadline, mo_date,
delta=timedelta(seconds=10),
msg="Schedule date of manufacturing order should be equal to: Schedule date of pack type picking - product's Manufacturing Lead Time."
)