diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 9ed07cb5f38..0cc564c7091 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -20,6 +20,7 @@ ############################################################################## from mx import DateTime +from datetime import datetime, timedelta from osv import osv, fields from tools.translate import _ import ir @@ -99,8 +100,8 @@ class mrp_routing_workcenter(osv.osv): 'name': fields.char('Name', size=64, required=True), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of routing workcenters."), 'cycle_nbr': fields.float('Number of Cycles', required=True, - help="Time in hours for doing one cycle."), - 'hour_nbr': fields.float('Number of Hours', required=True, help="Cost per hour"), + help="Number of operations this workcenter can do."), + 'hour_nbr': fields.float('Number of Hours', required=True, help="Time in hours for doing one cycle."), 'routing_id': fields.many2one('mrp.routing', 'Parent Routing', select=True, ondelete='cascade', help="Routing indicates all the workcenters used, for how long and/or cycles." \ "If Routing is indicated then,the third tab of a production order (workcenters) will be automatically pre-completed."), @@ -372,8 +373,6 @@ def rounding(f, r): class many2many_domain(fields.many2many): def set(self, cr, obj, id, name, values, user=None, context=None): - if not values: - return return super(many2many_domain, self).set(cr, obj, id, name, values, user=user, context=context) @@ -392,8 +391,6 @@ class many2many_domain(fields.many2many): class one2many_domain(fields.one2many): def set(self, cr, obj, id, field, values, user=None, context=None): - if not values: - return return super(one2many_domain, self).set(cr, obj, id, field, values, user=user, context=context) @@ -416,7 +413,6 @@ class mrp_production(osv.osv): _name = 'mrp.production' _description = 'Manufacturing Order' _date_name = 'date_planned' - _log_create = True def _production_calc(self, cr, uid, ids, prop, unknow_none, context={}): """ Calculates total hours and total no. of cycles for a production order. @@ -485,10 +481,10 @@ class mrp_production(osv.osv): 'picking_id': fields.many2one('stock.picking', 'Picking list', readonly=True, help="This is the internal picking list that brings the finished product to the production plan"), 'move_prod_id': fields.many2one('stock.move', 'Move product', readonly=True), - 'move_lines': many2many_domain('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products to Consumme', domain=[('state','not in', ('done', 'cancel'))]), - 'move_lines2': many2many_domain('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Consummed Products', domain=[('state','in', ('done', 'cancel'))]), - 'move_created_ids': one2many_domain('stock.move', 'production_id', 'Moves Created', domain=[('state','not in', ('done', 'cancel'))]), - 'move_created_ids2': one2many_domain('stock.move', 'production_id', 'Moves Created', domain=[('state','in', ('done', 'cancel'))]), + 'move_lines': many2many_domain('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products to Consumme', domain=[('state','not in', ('done', 'cancel'))], states={'done':[('readonly',True)]}), + 'move_lines2': many2many_domain('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Consummed Products', domain=[('state','in', ('done', 'cancel'))], readonly=True), + 'move_created_ids': one2many_domain('stock.move', 'production_id', 'Moves Created', domain=[('state','not in', ('done', 'cancel'))], states={'done':[('readonly',True)]}), + 'move_created_ids2': one2many_domain('stock.move', 'production_id', 'Moves Created', domain=[('state','in', ('done', 'cancel'))], readonly=True), 'product_lines': fields.one2many('mrp.production.product.line', 'production_id', 'Scheduled goods'), 'workcenter_lines': fields.one2many('mrp.production.workcenter.line', 'production_id', 'Work Centers Utilisation'), 'state': fields.selection([('draft','Draft'),('picking_except', 'Picking Exception'),('confirmed','Waiting Goods'),('ready','Ready to Produce'),('in_production','In Production'),('cancel','Cancelled'),('done','Done')],'State', readonly=True, @@ -508,7 +504,18 @@ class mrp_production(osv.osv): 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.production', context=c), } _order = 'date_planned asc, priority desc'; - + + def _check_qty(self, cr, uid, ids): + orders = self.browse(cr, uid, ids) + for order in orders: + if order.product_qty <= 0: + return False + return True + + _constraints = [ + (_check_qty, 'Order quantity cannot be negative or zero !', ['product_qty']), + ] + def unlink(self, cr, uid, ids, context=None): productions = self.read(cr, uid, ids, ['state']) unlink_ids = [] @@ -638,15 +645,23 @@ class mrp_production(osv.osv): """ Changes the production state to Ready and location id of stock move. @return: True """ - for (id,name) in self.name_get(cr, uid, ids): - message = _('Manufacturing Order ') + " '" + name + "' "+ _("is ready to produce.") - self.log(cr, uid, id, message) move_obj = self.pool.get('stock.move') self.write(cr, uid, ids, {'state': 'ready'}) - for production in self.browse(cr, uid, ids): + + for (production_id,name) in self.name_get(cr, uid, ids): + production = self.browse(cr, uid, production_id) if production.move_prod_id: move_obj.write(cr, uid, [production.move_prod_id.id], {'location_id': production.location_dest_id.id}) + + message = ("%s %s %s %s %s %s") % ( + _('Manufacturing Order '), + name, + _("scheduled the"), + datetime.strptime(production.date_planned,'%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d'), + _("for"), + production.product_id.name) + self.log(cr, uid, production_id, message) return True def action_production_end(self, cr, uid, ids): @@ -680,9 +695,10 @@ class mrp_production(osv.osv): @param production_mode: specify production mode (consume/consume&produce). @return: True """ + stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id) - + raw_product_todo = [] final_product_todo = [] @@ -692,6 +708,7 @@ class mrp_production(osv.osv): continue produced_qty += produced_product.product_qty + if production_mode in ['consume','consume_produce']: consumed_products = {} for consumed_product in production.move_lines2: @@ -700,12 +717,13 @@ class mrp_production(osv.osv): if not consumed_products.get(consumed_product.product_id.id, False): consumed_products[consumed_product.product_id.id] = 0 consumed_products[consumed_product.product_id.id] -= consumed_product.product_qty - + for raw_product in production.move_lines: for f in production.product_lines: if f.product_id.id==raw_product.product_id.id: consumed_qty = consumed_products.get(raw_product.product_id.id, 0) rest_qty = production_qty * f.product_qty / production.product_qty - consumed_qty + if rest_qty > 0: stock_mov_obj.action_consume(cr, uid, [raw_product.id], rest_qty, production.location_src_id.id, context=context) @@ -854,7 +872,7 @@ class mrp_production(osv.osv): 'company_id': production.company_id.id, } res_final_id = move_obj.create(cr, uid, data) - + self.write(cr, uid, [production.id], {'move_created_ids': [(6, 0, [res_final_id])]}) moves = [] for line in production.product_lines: diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 5eb86e77c49..d6cd8f573ab 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -67,16 +67,38 @@ - + + + + mrp.property.search + mrp.property + search + + + + + + + + + + + + + + + + Properties ir.actions.act_window mrp.property form tree,form + + + + @@ -148,12 +173,37 @@ + + + + + mrp.workcenter.search + mrp.workcenter + search + + + + + + + + + + + + + + + + + Work Centers ir.actions.act_window mrp.workcenter form +