Skip to content

Commit

Permalink
[IMP] stock*,mrp*: Dates Refactor
Browse files Browse the repository at this point in the history
- The deadline of MO generated via procurements is calculated differently.
Now, it doesn't take anymore in account the manufacturing_lead
of the company (Security Lead Time of MO). The computation of planned date remains unchanged.
- The date_expected fields was duplicated with the date fields
except when the move was done. Merge both fields.
The only information lost is: we can't know what was the
scheduled date before processing move (`state` == done).
Indeed, the date becomes the actual move processing datetime.
- The `date` in `stock.picking` field contained the time of
(purchase) order `date_order` (`purchase.order`).
This field is was wrongly used in the kanban view where we
expected to see date_planned instead. Also, the `_order` used
this date instead of date_planned too.
- The `delay_alert` is activate independently of stock rules.
Then it is now activate in all case.
- Remove the auto-reschedulting process of stock move via
the stock rule (`propagate_date` and `propagate_date_minimum_delta`).
Replace it by a automatic deadline date (`date_deadline`) propagation.
The deadline is the promise done to/by vendor/client (SO/PO)
then it is a readonly fields on picking/move and MO.
- Now the Scheduled date (`date`) of stock move is never propagate
and it is only related to the Scheduled date of
related document (MO or picking).
- Now when a move is created from procurement (sale),
`date_planned` = `date_deadline` - `security_lead`.
- The `delivery_date` of sale is no editable after confirmation
and propagate as the deadline to related stock move linked to order_line
- Adapt filter and decoration of MO and picking.
- Because we are the client in case of purchase (PO), the promise of vendor
can be not respected. Then we add the lead security to the deadline
(inverse the sale order logic) of PO picking (promise reciept date
+ security lead) to match with the replenishment.

task-2246665
  • Loading branch information
ryv-odoo committed Aug 18, 2020
1 parent e405537 commit 57f805f
Show file tree
Hide file tree
Showing 37 changed files with 362 additions and 958 deletions.
69 changes: 23 additions & 46 deletions addons/mrp/models/mrp_production.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,15 @@ def _get_default_is_locked(self):
help="Location where the system will stock the finished products.")
date_planned_start = fields.Datetime(
'Scheduled Date', copy=False, default=_get_default_date_planned_start,
compute='_compute_dates_planned', inverse='_set_date_planned_start',
help="Date at which you plan to start the production.",
index=True, required=True, store=True)
index=True, required=True)
date_planned_finished = fields.Datetime(
'Scheduled End Date',
default=_get_default_date_planned_finished,
compute='_compute_dates_planned', inverse='_set_date_planned_finished',
help="Date at which you plan to finish the production.",
copy=False, store=True)
copy=False)
date_deadline = fields.Datetime(
'Deadline', copy=False, index=True,
'Deadline', copy=False, store=True, readonly=True, compute='_compute_date_deadline', inverse='_set_date_deadline',
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)
Expand Down Expand Up @@ -225,13 +223,8 @@ def _get_default_is_locked(self):
propagate_cancel = fields.Boolean(
'Propagate cancel and split',
help='If checked, when the previous move of the move (which was generated by a next procurement) is cancelled or split, the move generated by this move will too')
delay_alert = fields.Boolean(string='Delay alert')
delay_alert_date = fields.Datetime('Delay Alert Date', compute='_compute_delay_alert_date', search='_search_delay_alert_date')
json_popover = fields.Char('JSON data for the popover widget', compute='_compute_json_popover')
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')
scrap_ids = fields.One2many('stock.scrap', 'production_id', 'Scraps')
scrap_count = fields.Integer(compute='_compute_scrap_move_count', string='Scrap Move')
is_locked = fields.Boolean('Is Locked', default=_get_default_is_locked, copy=False)
Expand Down Expand Up @@ -314,25 +307,14 @@ def _compute_components_availability(self):
production.components_availability = 'Not Available'
production.components_availability_state = 'late'


@api.depends('move_raw_ids.date_expected', 'move_finished_ids.date_expected')
def _compute_dates_planned(self):
@api.depends('move_finished_ids.date_deadline')
def _compute_date_deadline(self):
for production in self:
if production.state != 'done':
old_date = production.date_planned_start
production.date_planned_start = max(production.mapped('move_raw_ids.date_expected') or [fields.Datetime.now()])
if production.date_planned_start != old_date and production.is_planned:
production._plan_workorders(replan=True)
if production.move_finished_ids:
production.date_planned_finished = max(production.mapped('move_finished_ids.date_expected'))

def _set_date_planned_start(self):
if self.date_planned_start:
self.move_raw_ids.write({'date_expected': self.date_planned_start})
production.date_deadline = min(production.move_finished_ids.filtered('date_deadline').mapped('date_deadline'), default=production.date_deadline or False)

def _set_date_planned_finished(self):
if self.date_planned_finished:
self.move_finished_ids.write({'date_expected': self.date_planned_finished})
def _set_date_deadline(self):
for production in self:
(self.move_raw_ids | self.move_finished_ids).date_deadline = production.date_deadline

def _compute_is_planned(self):
for production in self:
Expand Down Expand Up @@ -602,8 +584,8 @@ def _onchange_date_planned_start(self):
if date_planned_finished == self.date_planned_start:
date_planned_finished = date_planned_finished + relativedelta(hours=1)
self.date_planned_finished = date_planned_finished
self.move_raw_ids = [(1, m.id, {'date_expected': self.date_planned_start, 'date': self.date_planned_start}) for m in self.move_raw_ids]
self.move_finished_ids = [(1, m.id, {'date_expected': date_planned_finished, 'date': date_planned_finished}) for m in self.move_finished_ids]
self.move_raw_ids = [(1, m.id, {'date': self.date_planned_start}) for m in self.move_raw_ids]
self.move_finished_ids = [(1, m.id, {'date': date_planned_finished}) for m in self.move_finished_ids]

@api.onchange('bom_id', 'product_id', 'product_qty', 'product_uom_id')
def _onchange_move_raw(self):
Expand Down Expand Up @@ -702,18 +684,22 @@ def write(self, vals):
raise UserError(_('You cannot move a manufacturing order once it is cancelled or done.'))
if production.is_partially_planned:
raise UserError(_('You cannot move a manufacturing order once it has a planned workorder, move related workorder(s) instead.'))
if vals.get('date_planned_start'):
production.move_raw_ids.write({'date': production.date_planned_start})
if vals.get('date_planned_finished'):
production.move_finished_ids.write({'date': production.date_planned_finished})
if any(field in ['move_raw_ids', 'move_finished_ids', 'workorder_ids'] for field in vals) and production.state != 'draft':
if production.state == 'done':
# for some reason moves added after state = 'done' won't save group_id, reference if added in
# "stock_move.default_get()"
production.move_raw_ids.filtered(lambda move: move.additional and move.date_expected > production.date_planned_start).write({
production.move_raw_ids.filtered(lambda move: move.additional and move.date > production.date_planned_start).write({
'group_id': production.procurement_group_id.id,
'reference': production.name,
'date_expected': production.date_planned_start,
'date': production.date_planned_start,
})
production.move_finished_ids.filtered(lambda move: move.additional and move.date_expected > production.date_planned_finished).write({
production.move_finished_ids.filtered(lambda move: move.additional and move.date > production.date_planned_finished).write({
'reference': production.name,
'date_expected': production.date_planned_finished,
'date': production.date_planned_finished,
})
production._autoconfirm_production()
if production in production_to_replan:
Expand Down Expand Up @@ -748,6 +734,8 @@ def create(self, values):
(production.move_raw_ids | production.move_finished_ids).write({
'group_id': production.procurement_group_id.id,
})
production.move_raw_ids.write({'date': production.date_planned_start})
production.move_finished_ids.write({'date': production.date_planned_finished})
# Trigger move_raw creation when importing a file
if 'import_file' in self.env.context:
production._onchange_move_raw()
Expand Down Expand Up @@ -817,7 +805,7 @@ def _get_move_finished_values(self, product_id, product_uom_qty, product_uom, op
'byproduct_id': byproduct_id,
'name': self.name,
'date': date_planned_finished,
'date_expected': date_planned_finished,
'date_deadline': self.date_deadline,
'picking_type_id': self.picking_type_id.id,
'location_id': self.product_id.with_company(self.company_id).property_stock_production.id,
'location_dest_id': self.location_dest_id.id,
Expand All @@ -827,9 +815,6 @@ def _get_move_finished_values(self, product_id, product_uom_qty, product_uom, op
'origin': self.name,
'group_id': self.procurement_group_id.id,
'propagate_cancel': self.propagate_cancel,
'propagate_date': self.propagate_date,
'delay_alert': self.delay_alert,
'propagate_date_minimum_delta': self.propagate_date_minimum_delta,
'move_dest_ids': [(4, x.id) for x in move_dest_ids],
}

Expand Down Expand Up @@ -872,7 +857,7 @@ def _get_move_raw_values(self, product_id, product_uom_qty, product_uom, operati
'sequence': bom_line.sequence if bom_line else 10,
'name': self.name,
'date': self.date_planned_start,
'date_expected': self.date_planned_start,
'date_deadline': self.date_deadline,
'bom_line_id': bom_line.id if bom_line else False,
'picking_type_id': self.picking_type_id.id,
'product_id': product_id.id,
Expand All @@ -890,9 +875,6 @@ def _get_move_raw_values(self, product_id, product_uom_qty, product_uom, operati
'warehouse_id': source_location.get_warehouse().id,
'group_id': self.procurement_group_id.id,
'propagate_cancel': self.propagate_cancel,
'propagate_date': self.propagate_date,
'propagate_date_minimum_delta': self.propagate_date_minimum_delta,
'delay_alert': self.delay_alert
}
return data

Expand Down Expand Up @@ -1101,11 +1083,6 @@ def button_plan(self):
orders_to_plan = self.filtered(lambda order: not order.is_planned)
for order in orders_to_plan:
(order.move_raw_ids | order.move_finished_ids).filtered(lambda m: m.state == 'draft')._action_confirm()
# `propagate_date` enables the automatic rescheduling which could lead to hard to
# understand behavior if a manufacturing order is planned, i.e. if the work orders do
# have their leaves booked in the workcenter calendar. We thus disable the
# automatic rescheduling in this scenario.
order.move_raw_ids.write({'propagate_date': False})
order._plan_workorders()
return True

Expand Down
8 changes: 3 additions & 5 deletions addons/mrp/models/stock_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ def _get_matching_bom(self, product_id, company_id, values):
product=product_id, picking_type=self.picking_type_id, bom_type='normal', company_id=company_id.id)

def _prepare_mo_vals(self, product_id, product_qty, product_uom, location_id, name, origin, company_id, values, bom):
date_deadline = fields.Datetime.to_string(self._get_date_planned(product_id, company_id, values))
date_planned = self._get_date_planned(product_id, company_id, values)
date_deadline = values.get('date_deadline') or date_planned + relativedelta(days=company_id.manufacturing_lead) # Remove manufacturing security of deadline
return {
'origin': origin,
'product_id': product_id.id,
Expand All @@ -95,12 +96,9 @@ def _prepare_mo_vals(self, product_id, product_qty, product_uom, location_id, na
'location_dest_id': location_id.id,
'bom_id': bom.id,
'date_deadline': date_deadline,
'date_planned_start': date_deadline,
'date_planned_start': date_planned,
'procurement_group_id': False,
'delay_alert': self.delay_alert,
'propagate_cancel': self.propagate_cancel,
'propagate_date': self.propagate_date,
'propagate_date_minimum_delta': self.propagate_date_minimum_delta,
'orderpoint_id': values.get('orderpoint_id', False) and values.get('orderpoint_id').id,
'picking_type_id': self.picking_type_id.id or values['warehouse_id'].manu_type_id.id,
'company_id': company_id.id,
Expand Down
Loading

0 comments on commit 57f805f

Please sign in to comment.