[ADD]:Added Upstream Patch for mrp
This commit is contained in:
parent
a861b436a1
commit
0da768c114
@ -80,6 +80,8 @@ class MrpBom(models.Model):
|
||||
def onchange_product_tmpl_id(self):
|
||||
if self.product_tmpl_id:
|
||||
self.product_uom_id = self.product_tmpl_id.uom_id.id
|
||||
if self.product_id.product_tmpl_id != self.product_tmpl_id:
|
||||
self.product_id = False
|
||||
|
||||
@api.onchange('routing_id')
|
||||
def onchange_routing_id(self):
|
||||
|
@ -389,7 +389,7 @@ class MrpProduction(models.Model):
|
||||
source_location = routing.location_id
|
||||
else:
|
||||
source_location = self.location_src_id
|
||||
original_quantity = self.product_qty - self.qty_produced
|
||||
original_quantity = (self.product_qty - self.qty_produced) or 1.0
|
||||
data = {
|
||||
'sequence': bom_line.sequence,
|
||||
'name': self.name,
|
||||
@ -474,10 +474,16 @@ class MrpProduction(models.Model):
|
||||
@api.multi
|
||||
def _generate_workorders(self, exploded_boms):
|
||||
workorders = self.env['mrp.workorder']
|
||||
original_one = False
|
||||
for bom, bom_data in exploded_boms:
|
||||
# If the routing of the parent BoM and phantom BoM are the same, don't recreate work orders, but use one master routing
|
||||
if bom.routing_id.id and (not bom_data['parent_line'] or bom_data['parent_line'].bom_id.routing_id.id != bom.routing_id.id):
|
||||
workorders += self._workorders_create(bom, bom_data)
|
||||
temp_workorders = self._workorders_create(bom, bom_data)
|
||||
workorders += temp_workorders
|
||||
if temp_workorders: # In order to avoid two "ending work orders"
|
||||
if original_one:
|
||||
temp_workorders[-1].next_work_order_id = original_one
|
||||
original_one = temp_workorders[0]
|
||||
return workorders
|
||||
|
||||
def _workorders_create(self, bom, bom_data):
|
||||
@ -558,7 +564,7 @@ class MrpProduction(models.Model):
|
||||
order._cal_price(moves_to_do)
|
||||
moves_to_finish = order.move_finished_ids.filtered(lambda x: x.state not in ('done','cancel'))
|
||||
moves_to_finish._action_done()
|
||||
#order.action_assign()
|
||||
order.action_assign()
|
||||
consume_move_lines = moves_to_do.mapped('active_move_line_ids')
|
||||
for moveline in moves_to_finish.mapped('active_move_line_ids'):
|
||||
if moveline.product_id == order.product_id and moveline.move_id.has_tracking != 'none':
|
||||
|
@ -219,6 +219,7 @@ class MrpWorkorder(models.Model):
|
||||
'done_wo': False,
|
||||
'location_id': move.location_id.id,
|
||||
'location_dest_id': move.location_dest_id.id,
|
||||
'date': move.date,
|
||||
})
|
||||
qty_todo -= 1
|
||||
elif float_compare(qty_todo, 0.0, precision_rounding=rounding) < 0:
|
||||
@ -284,6 +285,18 @@ class MrpWorkorder(models.Model):
|
||||
self.final_lot_id = self.env['stock.production.lot'].search([('use_next_on_work_order_id', '=', self.id)],
|
||||
order='create_date, id', limit=1)
|
||||
|
||||
def _get_byproduct_move_line(self, by_product_move, quantity):
|
||||
return {
|
||||
'move_id': by_product_move.id,
|
||||
'product_id': by_product_move.product_id.id,
|
||||
'product_uom_qty': quantity,
|
||||
'product_uom_id': by_product_move.product_uom.id,
|
||||
'qty_done': quantity,
|
||||
'workorder_id': self.id,
|
||||
'location_id': by_product_move.location_id.id,
|
||||
'location_dest_id': by_product_move.location_dest_id.id,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def record_production(self):
|
||||
self.ensure_one()
|
||||
@ -339,33 +352,37 @@ class MrpWorkorder(models.Model):
|
||||
# If last work order, then post lots used
|
||||
# TODO: should be same as checking if for every workorder something has been done?
|
||||
if not self.next_work_order_id:
|
||||
production_moves = self.production_id.move_finished_ids.filtered(lambda x: (x.state not in ('done', 'cancel')))
|
||||
for production_move in production_moves:
|
||||
if production_move.product_id.id == self.production_id.product_id.id and production_move.has_tracking != 'none':
|
||||
move_line = production_move.move_line_ids.filtered(lambda x: x.lot_id.id == self.final_lot_id.id)
|
||||
if move_line:
|
||||
move_line.product_uom_qty += self.qty_producing
|
||||
else:
|
||||
move_line.create({'move_id': production_move.id,
|
||||
'product_id': production_move.product_id.id,
|
||||
'lot_id': self.final_lot_id.id,
|
||||
'product_uom_qty': self.qty_producing,
|
||||
'product_uom_id': production_move.product_uom.id,
|
||||
'qty_done': self.qty_producing,
|
||||
'workorder_id': self.id,
|
||||
'location_id': production_move.location_id.id,
|
||||
'location_dest_id': production_move.location_dest_id.id,
|
||||
})
|
||||
elif production_move.unit_factor:
|
||||
rounding = production_move.product_uom.rounding
|
||||
production_move.quantity_done += float_round(self.qty_producing * production_move.unit_factor, precision_rounding=rounding)
|
||||
production_move = self.production_id.move_finished_ids.filtered(
|
||||
lambda x: (x.product_id.id == self.production_id.product_id.id) and (x.state not in ('done', 'cancel')))
|
||||
if production_move.product_id.tracking != 'none':
|
||||
move_line = production_move.move_line_ids.filtered(lambda x: x.lot_id.id == self.final_lot_id.id)
|
||||
if move_line:
|
||||
move_line.product_uom_qty += self.qty_producing
|
||||
move_line.qty_done += self.qty_producing
|
||||
else:
|
||||
production_move.quantity_done += self.qty_producing
|
||||
move_line.create({'move_id': production_move.id,
|
||||
'product_id': production_move.product_id.id,
|
||||
'lot_id': self.final_lot_id.id,
|
||||
'product_uom_qty': self.qty_producing,
|
||||
'product_uom_id': production_move.product_uom.id,
|
||||
'qty_done': self.qty_producing,
|
||||
'workorder_id': self.id,
|
||||
'location_id': production_move.location_id.id,
|
||||
'location_dest_id': production_move.location_dest_id.id,
|
||||
})
|
||||
else:
|
||||
production_move.quantity_done += self.qty_producing
|
||||
|
||||
if not self.next_work_order_id:
|
||||
for by_product_move in self.production_id.move_finished_ids.filtered(lambda x: (x.product_id.id != self.production_id.product_id.id) and (x.state not in ('done', 'cancel'))):
|
||||
if by_product_move.has_tracking == 'none':
|
||||
by_product_move.quantity_done += self.qty_producing * by_product_move.unit_factor
|
||||
if by_product_move.has_tracking != 'serial':
|
||||
values = self._get_byproduct_move_line(by_product_move, self.qty_producing * by_product_move.unit_factor)
|
||||
self.env['stock.move.line'].create(values)
|
||||
elif by_product_move.has_tracking == 'serial':
|
||||
qty_todo = by_product_move.product_uom._compute_quantity(self.qty_producing * by_product_move.unit_factor, by_product_move.product_id.uom_id)
|
||||
for i in range(0, int(float_round(qty_todo, precision_digits=0))):
|
||||
values = self._get_byproduct_move_line(by_product_move, 1)
|
||||
self.env['stock.move.line'].create(values)
|
||||
|
||||
# Update workorder quantity produced
|
||||
self.qty_produced += self.qty_producing
|
||||
@ -395,7 +412,12 @@ class MrpWorkorder(models.Model):
|
||||
|
||||
@api.multi
|
||||
def button_start(self):
|
||||
# TDE CLEANME
|
||||
self.ensure_one()
|
||||
# As button_start is automatically called in the new view
|
||||
if self.state in ('done', 'cancel'):
|
||||
return True
|
||||
|
||||
# Need a loss in case of the real time exceeding the expected
|
||||
timeline = self.env['mrp.workcenter.productivity']
|
||||
if self.duration < self.duration_expected:
|
||||
loss_id = self.env['mrp.workcenter.productivity.loss'].search([('loss_type','=','productive')], limit=1)
|
||||
|
@ -73,6 +73,13 @@ class StockMove(models.Model):
|
||||
order_finished_lot_ids = fields.Many2many('stock.production.lot', compute='_compute_order_finished_lot_ids')
|
||||
finished_lots_exist = fields.Boolean('Finished Lots Exist', compute='_compute_order_finished_lot_ids')
|
||||
|
||||
def _unreserve_initial_demand(self, new_move):
|
||||
# If you were already putting stock.move.lots on the next one in the work order, transfer those to the new move
|
||||
self.filtered(lambda m: m.production_id or m.raw_material_production_id)\
|
||||
.mapped('move_line_ids')\
|
||||
.filtered(lambda ml: ml.qty_done == 0.0)\
|
||||
.write({'move_id': new_move, 'product_uom_qty': 0})
|
||||
|
||||
@api.depends('active_move_line_ids.qty_done', 'active_move_line_ids.product_uom_id')
|
||||
def _compute_done_quantity(self):
|
||||
super(StockMove, self)._compute_done_quantity()
|
||||
|
@ -29,12 +29,12 @@ class StockWarehouse(models.Model):
|
||||
return result
|
||||
|
||||
def _get_manufacture_route_id(self):
|
||||
manufacture_route_id = self.env.ref('mrp.route_warehouse0_manufacture').id
|
||||
if not manufacture_route_id:
|
||||
manufacture_route_id = self.env['stock.location.route'].search([('name', 'like', _('Manufacture'))], limit=1).id
|
||||
if not manufacture_route_id:
|
||||
manufacture_route = self.env.ref('mrp.route_warehouse0_manufacture', raise_if_not_found=False)
|
||||
if not manufacture_route:
|
||||
manufacture_route = self.env['stock.location.route'].search([('name', 'like', _('Manufacture'))], limit=1)
|
||||
if not manufacture_route:
|
||||
raise exceptions.UserError(_('Can\'t find any generic Manufacture route.'))
|
||||
return manufacture_route_id
|
||||
return manufacture_route.id
|
||||
|
||||
def _get_manufacture_pull_rules_values(self, route_values):
|
||||
if not self.manu_type_id:
|
||||
|
@ -36,7 +36,7 @@
|
||||
<span t-att-res-id="bom_line['product_id'].id" res-model="product.product" view-type="form" t-esc="bom_line['product_id'].name"/>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span t-esc="bom_line['product_uom_qty']"/> <span t-esc="bom_line['product_uom'].name" groups="product.group_uom"/>
|
||||
<span t-esc="bom_line['product_uom_qty']" t-esc-options='{"widget": "float", "decimal_precision": "Product Unit of Measure"}'/> <span t-esc="bom_line['product_uom'].name" groups="product.group_uom"/>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span t-esc="bom_line['price_unit']" t-options='{"widget": "monetary", "display_currency": currency}'/>
|
||||
|
@ -7,36 +7,49 @@ from flectra import api, models
|
||||
class BomStructureReport(models.AbstractModel):
|
||||
_name = 'report.mrp.mrp_bom_structure_report'
|
||||
|
||||
def get_children(self, object, level=0):
|
||||
@api.model
|
||||
def _get_child_vals(self, record, level, qty, uom):
|
||||
"""Get bom.line values.
|
||||
|
||||
:param record: mrp.bom.line record
|
||||
:param level: level of recursion
|
||||
:param qty: quantity of the product
|
||||
:param uom: unit of measurement of a product
|
||||
"""
|
||||
child = {
|
||||
'pname': record.product_id.name_get()[0][1],
|
||||
'pcode': record.product_id.default_code,
|
||||
'puom': record.product_uom_id,
|
||||
'uname': record.product_uom_id.name,
|
||||
'level': level,
|
||||
'code': record.bom_id.code,
|
||||
}
|
||||
qty_per_bom = record.bom_id.product_qty
|
||||
if uom:
|
||||
if uom != record.bom_id.product_uom_id:
|
||||
qty = uom._compute_quantity(qty, record.bom_id.product_uom_id)
|
||||
child['pqty'] = (record.product_qty * qty) / qty_per_bom
|
||||
else:
|
||||
# for the first case, the ponderation is right
|
||||
child['pqty'] = (record.product_qty * qty)
|
||||
return child
|
||||
|
||||
def get_children(self, records, level=0):
|
||||
result = []
|
||||
|
||||
def _get_rec(object, level, qty=1.0, uom=False):
|
||||
for l in object:
|
||||
res = {}
|
||||
res['pname'] = l.product_id.name_get()[0][1]
|
||||
res['pcode'] = l.product_id.default_code
|
||||
qty_per_bom = l.bom_id.product_qty
|
||||
if uom:
|
||||
if uom != l.bom_id.product_uom_id:
|
||||
qty = uom._compute_quantity(qty, l.bom_id.product_uom_id)
|
||||
res['pqty'] = (l.product_qty *qty)/ qty_per_bom
|
||||
else:
|
||||
#for the first case, the ponderation is right
|
||||
res['pqty'] = (l.product_qty *qty)
|
||||
res['puom'] = l.product_uom_id
|
||||
res['uname'] = l.product_uom_id.name
|
||||
res['level'] = level
|
||||
res['code'] = l.bom_id.code
|
||||
result.append(res)
|
||||
def _get_rec(records, level, qty=1.0, uom=False):
|
||||
for l in records:
|
||||
child = self._get_child_vals(l, level, qty, uom)
|
||||
result.append(child)
|
||||
if l.child_line_ids:
|
||||
if level < 6:
|
||||
level += 1
|
||||
_get_rec(l.child_line_ids, level, qty=res['pqty'], uom=res['puom'])
|
||||
_get_rec(l.child_line_ids, level, qty=child['pqty'], uom=child['puom'])
|
||||
if level > 0 and level < 6:
|
||||
level -= 1
|
||||
return result
|
||||
|
||||
children = _get_rec(object, level)
|
||||
children = _get_rec(records, level)
|
||||
|
||||
return children
|
||||
|
||||
|
@ -126,7 +126,7 @@
|
||||
<field name="state" invisible="1" force_save="1"/>
|
||||
<field name="product_uom_qty" string="To Consume"/>
|
||||
<field name="reserved_availability" attrs="{'invisible': [('is_done', '=', True)]}" string="Reserved"/>
|
||||
<field name="quantity_done" string="Consumed"/>
|
||||
<field name="quantity_done" string="Consumed" readonly="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
@ -177,4 +177,4 @@
|
||||
groups="group_mrp_routings"
|
||||
sequence="50"/>
|
||||
</data>
|
||||
</flectra>
|
||||
</flectra>
|
@ -190,18 +190,19 @@
|
||||
<label for="duration"/>
|
||||
<div>
|
||||
<button style="pointer-events: none;" class="oe_inline label label-default">
|
||||
<field name="duration" widget="mrp_time_counter"/>
|
||||
<field name="duration" widget="mrp_time_counter" help="Time the currently logged user spent on this workorder."/>
|
||||
</button>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="time_ids" nolabel="1">
|
||||
<field name="time_ids" nolabel="1" context="{'default_workcenter_id': workcenter_id}">
|
||||
<tree>
|
||||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<field name="duration" widget="float_time" sum="Total duration"/>
|
||||
<field name="user_id"/>
|
||||
<field name="workcenter_id" invisible="1"/>
|
||||
<field name="loss_id" string="Efficiency"/>
|
||||
</tree>
|
||||
<form>
|
||||
@ -213,6 +214,7 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_id"/>
|
||||
<field name="workcenter_id"/>
|
||||
<field name="loss_id"/>
|
||||
</group>
|
||||
</group>
|
||||
@ -404,6 +406,8 @@
|
||||
<field name="context">{'search_default_ready': True, 'search_default_progress': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to start a new work order.
|
||||
</p><p>
|
||||
Work Orders are operations to be processed at a Work Center to realize a
|
||||
Manufacturing Order. Work Orders are trigerred by Manufacturing Orders,
|
||||
they are based on the Routing defined on these ones.
|
||||
|
@ -22,7 +22,7 @@
|
||||
<label for="product_uom_qty"/>
|
||||
<div class="o_row">
|
||||
<span><field name="product_uom_qty" readonly="1" nolabel="1"/></span>
|
||||
<span><field name="product_uom" attrs="{'readonly': [('id', '!=', False)]}" nolabel="1"/></span>
|
||||
<span><field name="product_uom" readonly="1" force_save="1" nolabel="1"/></span>
|
||||
</div>
|
||||
<label for="quantity_done"/>
|
||||
<div class="o_row">
|
||||
@ -44,7 +44,7 @@
|
||||
<field name="finished_lots_exist" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="active_move_line_ids" attrs="{'readonly': [('is_locked', '=', True)], 'invisible': [('has_tracking', '=', 'none'), ('finished_lots_exist', '=', False)]}" context="{'default_workorder_id': workorder_id, 'default_product_uom_id': product_uom, 'default_product_id': product_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id, 'default_production_id': production_id or raw_material_production_id}">
|
||||
<field name="active_move_line_ids" attrs="{'readonly': [('is_locked', '=', True)]}" context="{'default_workorder_id': workorder_id, 'default_product_uom_id': product_uom, 'default_product_id': product_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id, 'default_production_id': production_id or raw_material_production_id}">
|
||||
<tree editable="bottom" decoration-success="product_qty==qty_done" decoration-danger="(product_qty > 0) and (qty_done>product_qty)">
|
||||
<field name="lot_id" attrs="{'column_invisible': [('parent.has_tracking', '=', 'none')]}" domain="[('product_id', '=', parent.product_id)]" context="{'default_product_id': parent.product_id}"/>
|
||||
<field name="lot_produced_id" options="{'no_open': True, 'no_create': True}" domain="[('id', 'in', parent.order_finished_lot_ids)]" invisible="not context.get('final_lots')"/>
|
||||
|
@ -43,7 +43,8 @@ class ChangeProductionQty(models.TransientModel):
|
||||
production = wizard.mo_id
|
||||
produced = sum(production.move_finished_ids.filtered(lambda m: m.product_id == production.product_id).mapped('quantity_done'))
|
||||
if wizard.product_qty < produced:
|
||||
raise UserError(_("You have already processed %d. Please input a quantity higher than %d ")%(produced, produced))
|
||||
format_qty = '%.{precision}f'.format(precision=precision)
|
||||
raise UserError(_("You have already processed %s. Please input a quantity higher than %s ") % (format_qty % produced, format_qty % produced))
|
||||
production.write({'product_qty': wizard.product_qty})
|
||||
done_moves = production.move_finished_ids.filtered(lambda x: x.state == 'done' and x.product_id == production.product_id)
|
||||
qty_produced = production.product_id.uom_id._compute_quantity(sum(done_moves.mapped('product_qty')), production.product_uom_id)
|
||||
|
@ -38,7 +38,8 @@ class MrpProductProduce(models.TransientModel):
|
||||
if 'produce_line_ids' in fields:
|
||||
lines = []
|
||||
for move in production.move_raw_ids.filtered(lambda x: (x.product_id.tracking != 'none') and x.state not in ('done', 'cancel') and x.bom_line_id):
|
||||
qty_to_consume = todo_quantity / move.bom_line_id.bom_id.product_qty * move.bom_line_id.product_qty
|
||||
qty_to_consume = float_round(todo_quantity / move.bom_line_id.bom_id.product_qty * move.bom_line_id.product_qty,
|
||||
precision_rounding=move.product_uom.rounding, rounding_method="UP")
|
||||
for move_line in move.move_line_ids:
|
||||
if float_compare(qty_to_consume, 0.0, precision_rounding=move.product_uom.rounding) <= 0:
|
||||
break
|
||||
@ -176,9 +177,9 @@ class MrpProductProduceLine(models.TransientModel):
|
||||
product_produce_id = fields.Many2one('mrp.product.produce')
|
||||
product_id = fields.Many2one('product.product', 'Product')
|
||||
lot_id = fields.Many2one('stock.production.lot', 'Lot')
|
||||
qty_to_consume = fields.Float('To Consume')
|
||||
qty_to_consume = fields.Float('To Consume', digits=dp.get_precision('Product Unit of Measure'))
|
||||
product_uom_id = fields.Many2one('product.uom', 'Unit of Measure')
|
||||
qty_done = fields.Float('Done')
|
||||
qty_done = fields.Float('Done', digits=dp.get_precision('Product Unit of Measure'))
|
||||
move_id = fields.Many2one('stock.move')
|
||||
|
||||
@api.onchange('lot_id')
|
||||
|
Loading…
Reference in New Issue
Block a user