[ADD]:Added Upstream Patch for mrp

This commit is contained in:
Fatemi Lokhandwala 2018-07-09 18:07:58 +05:30
parent a861b436a1
commit 0da768c114
13 changed files with 120 additions and 64 deletions

View File

@ -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):

View File

@ -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':

View File

@ -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)

View File

@ -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()

View File

@ -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:

View File

@ -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}'/>

View File

@ -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

View File

@ -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>

View File

@ -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.

View File

@ -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 &gt; 0) and (qty_done&gt;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')"/>

View File

@ -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)

View File

@ -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')