odoo/addons/mrp/wizard/mrp_product_produce.py

134 lines
7.1 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from odoo import api, fields, models, _
from odoo.addons import decimal_precision as dp
from odoo.exceptions import UserError
from odoo.tools import float_compare, float_round
class MrpProductProduce(models.TransientModel):
_name = "mrp.product.produce"
_description = "Record Production"
@api.model
def default_get(self, fields):
res = super(MrpProductProduce, self).default_get(fields)
if self._context and self._context.get('active_id'):
production = self.env['mrp.production'].browse(self._context['active_id'])
#serial_raw = production.move_raw_ids.filtered(lambda x: x.product_id.tracking == 'serial')
main_product_moves = production.move_finished_ids.filtered(lambda x: x.product_id.id == production.product_id.id)
serial_finished = (production.product_id.tracking == 'serial')
serial = bool(serial_finished)
if serial_finished:
quantity = 1.0
else:
quantity = production.product_qty - sum(main_product_moves.mapped('quantity_done'))
quantity = quantity if (quantity > 0) else 0
lines = []
existing_lines = []
for move in production.move_raw_ids.filtered(lambda x: (x.product_id.tracking != 'none') and x.state not in ('done', 'cancel')):
if not move.move_lot_ids.filtered(lambda x: not x.lot_produced_id):
qty = quantity / move.bom_line_id.bom_id.product_qty * move.bom_line_id.product_qty
if move.product_id.tracking == 'serial':
while float_compare(qty, 0.0, precision_rounding=move.product_uom.rounding) > 0:
lines.append({
'move_id': move.id,
'quantity': min(1,qty),
'quantity_done': 0.0,
'plus_visible': True,
'product_id': move.product_id.id,
'production_id': production.id,
})
qty -= 1
else:
lines.append({
'move_id': move.id,
'quantity': qty,
'quantity_done': 0.0,
'plus_visible': True,
'product_id': move.product_id.id,
'production_id': production.id,
})
else:
existing_lines += move.move_lot_ids.filtered(lambda x: not x.lot_produced_id).ids
res['serial'] = serial
res['production_id'] = production.id
res['product_qty'] = quantity
res['product_id'] = production.product_id.id
res['product_uom_id'] = production.product_uom_id.id
res['consume_line_ids'] = map(lambda x: (0,0,x), lines) + map(lambda x:(4, x), existing_lines)
return res
serial = fields.Boolean('Requires Serial')
production_id = fields.Many2one('mrp.production', 'Production')
product_id = fields.Many2one('product.product', 'Product')
product_qty = fields.Float(string='Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True)
product_uom_id = fields.Many2one('product.uom', 'Unit of Measure')
lot_id = fields.Many2one('stock.production.lot', string='Lot')
consume_line_ids = fields.Many2many('stock.move.lots', 'mrp_produce_stock_move_lots', string='Product to Track')
product_tracking = fields.Selection(related="product_id.tracking")
@api.multi
def do_produce(self):
# Nothing to do for lots since values are created using default data (stock.move.lots)
moves = self.production_id.move_raw_ids
quantity = self.product_qty
if float_compare(quantity, 0, precision_rounding=self.product_uom_id.rounding) <= 0:
raise UserError(_('You should at least produce some quantity'))
for move in moves.filtered(lambda x: x.product_id.tracking == 'none' and x.state not in ('done', 'cancel')):
if move.unit_factor:
rounding = move.product_uom.rounding
move.quantity_done_store += float_round(quantity * move.unit_factor, precision_rounding=rounding)
moves = self.production_id.move_finished_ids.filtered(lambda x: x.product_id.tracking == 'none' and x.state not in ('done', 'cancel'))
for move in moves:
rounding = move.product_uom.rounding
if move.product_id.id == self.production_id.product_id.id:
move.quantity_done_store += float_round(quantity, precision_rounding=rounding)
elif move.unit_factor:
# byproducts handling
move.quantity_done_store += float_round(quantity * move.unit_factor, precision_rounding=rounding)
self.check_finished_move_lots()
if self.production_id.state == 'confirmed':
self.production_id.write({
'state': 'progress',
'date_start': datetime.now(),
})
return {'type': 'ir.actions.act_window_close'}
@api.multi
def check_finished_move_lots(self):
lots = self.env['stock.move.lots']
produce_move = self.production_id.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel'))
if produce_move and produce_move.product_id.tracking != 'none':
if not self.lot_id:
raise UserError(_('You need to provide a lot for the finished product'))
existing_move_lot = produce_move.move_lot_ids.filtered(lambda x: x.lot_id == self.lot_id)
if existing_move_lot:
existing_move_lot.quantity += self.product_qty
existing_move_lot.quantity_done += self.product_qty
else:
vals = {
'move_id': produce_move.id,
'product_id': produce_move.product_id.id,
'production_id': self.production_id.id,
'quantity': self.product_qty,
'quantity_done': self.product_qty,
'lot_id': self.lot_id.id,
}
lots.create(vals)
for move in self.production_id.move_raw_ids:
for movelots in move.move_lot_ids.filtered(lambda x: not x.lot_produced_id):
if movelots.quantity_done and self.lot_id:
#Possibly the entire move is selected
remaining_qty = movelots.quantity - movelots.quantity_done
if remaining_qty > 0:
default = {'quantity': movelots.quantity_done, 'lot_produced_id': self.lot_id.id}
new_move_lot = movelots.copy(default=default)
movelots.write({'quantity': remaining_qty, 'quantity_done': 0})
else:
movelots.write({'lot_produced_id': self.lot_id.id})
return True