# -*- encoding: utf-8 -*- ############################################################################## # # OpenERP, Open Source Management Solution # dmr Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved # $Id$ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ############################################################################## from osv import fields from osv import osv import ir import datetime import netsvc import time from mx import DateTime from tools.translate import _ #---------------------------------------------------------- # Workcenters #---------------------------------------------------------- # capacity_hour : capacity per hour. default: 1.0. # Eg: If 5 concurrent operations at one time: capacity = 5 (because 5 employees) # unit_per_cycle : how many units are produced for one cycle # # TODO: Work Center may be recursive ? # class stock_move(osv.osv): _inherit = 'stock.move' _columns = { 'move_dest_id_lines': fields.one2many('stock.move','move_dest_id', 'Children Moves') } stock_move() class mrp_production_workcenter_line(osv.osv): def _get_date_date(self, cr, uid, ids, field_name, arg, context): res={} for op in self.browse(cr, uid, ids, context=context): if op.date_start: res[op.id] = op.date_start[:10] else: res[op.id]=False return res def _get_date_end(self, cr, uid, ids, field_name, arg, context): res = {} for op in self.browse(cr, uid, ids, context=context): res[op.id]= False if op.date_planned: d = DateTime.strptime(op.date_planned,'%Y-%m-%d %H:%M:%S') i = self.pool.get('hr.timesheet.group').interval_get(cr, uid, op.workcenter_id.timesheet_id.id or False, d, op.hour or 0.0) if i: res[op.id] = i[-1][1].strftime('%Y-%m-%d %H:%M:%S') else: res[op.id] = op.date_planned return res _inherit = 'mrp.production.workcenter.line' _order = "sequence, date_planned" _columns = { 'state': fields.selection([('draft','Draft'),('startworking', 'In Progress'),('pause','Pause'),('cancel','Canceled'),('done','Finished')],'Status', readonly=True), 'date_start_date': fields.function(_get_date_date, method=True, string='Start Date', type='date'), 'date_planned': fields.datetime('Scheduled Date'), 'date_planned_end': fields.function(_get_date_end, method=True, string='End Date', type='datetime'), 'date_start': fields.datetime('Start Date'), 'date_finnished': fields.datetime('End Date'), 'delay': fields.float('Working Hours',help="This is delay between operation start and stop in this workcenter",readonly=True), 'production_state':fields.related('production_id','state', type='selection', selection=[('draft','Draft'),('picking_except', 'Packing Exception'),('confirmed','Waiting Goods'),('ready','Ready to Produce'),('in_production','In Production'),('cancel','Canceled'),('done','Done')], string='Prod.State', readonly=True), 'product':fields.related('production_id','product_id',type='many2one',relation='product.product',string='Product', readonly=True), 'qty':fields.related('production_id','product_qty',type='float',string='Qty',readonly=True), 'uom':fields.related('production_id','product_uom',type='many2one',relation='product.uom',string='UOM',readonly=True), } _defaults = { 'state': lambda *a: 'draft', 'delay': lambda *a: 0.0 } def modify_production_order_state(self,cr,uid,ids,action): wf_service = netsvc.LocalService("workflow") oper_obj=self.browse(cr,uid,ids)[0] prod_obj=oper_obj.production_id if action=='start': if prod_obj.state =='confirmed': self.pool.get('mrp.production').force_production(cr, uid, [prod_obj.id]) wf_service.trg_validate(uid, 'mrp.production', prod_obj.id, 'button_produce', cr) elif prod_obj.state =='ready': wf_service.trg_validate(uid, 'mrp.production', prod_obj.id, 'button_produce', cr) elif prod_obj.state =='in_production': return else: raise osv.except_osv(_('Error!'),_('Production Order Cannot start in [%s] state') % (prod_obj.state,)) else: oper_ids=self.search(cr,uid,[('production_id','=',prod_obj.id)]) obj=self.browse(cr,uid,oper_ids) flag=True for line in obj: if line.state!='done': flag=False if flag: wf_service.trg_validate(uid, 'mrp.production', oper_obj.production_id.id, 'button_produce_done', cr) return def write(self, cr, uid, ids, vals, context={}, update=True): result = super(mrp_production_workcenter_line, self).write(cr, uid, ids, vals, context=context) if vals.get('date_planned', False) and update: pids = {} pids2 = {} for prod in self.browse(cr, uid, ids, context=context): if prod.production_id.workcenter_lines: dstart = min(vals['date_planned'], prod.production_id.workcenter_lines[0]['date_planned']) self.pool.get('mrp.production').write(cr, uid, [prod.production_id.id], {'date_start':dstart}, context=context, mini=False) return result def action_draft(self, cr, uid, ids): self.write(cr, uid, ids, {'state':'draft'}) return True def action_start_working(self, cr, uid, ids): self.modify_production_order_state(cr,uid,ids,'start') self.write(cr, uid, ids, {'state':'startworking', 'date_start': time.strftime('%Y-%m-%d %H:%M:%S')}) return True def action_done(self, cr, uid, ids): self.write(cr, uid, ids, {'state':'done', 'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')}) self.modify_production_order_state(cr,uid,ids,'done') return True def action_cancel(self, cr, uid, ids): self.write(cr, uid, ids, {'state':'cancel'}) return True def action_pause(self, cr, uid, ids): self.write(cr, uid, ids, {'state':'pause'}) return True def action_resume(self, cr, uid, ids): self.write(cr, uid, ids, {'state':'startworking'}) return True mrp_production_workcenter_line() class mrp_production(osv.osv): _inherit = 'mrp.production' _columns = { 'allow_reorder': fields.boolean('Free Serialisation', help="Check this to be able to move independently all production orders, without moving dependent ones."), } def _production_date_end(self, cr, uid, ids, prop, unknow_none, context={}): result = {} for prod in self.browse(cr, uid, ids, context=context): result[prod.id] = prod.date_planned for line in prod.workcenter_lines: result[prod.id] = max(line.date_planned_end, result[prod.id]) return result def action_production_end(self, cr, uid, ids): obj=self.browse(cr,uid,ids)[0] for workcenter_line in obj.workcenter_lines: tmp=self.pool.get('mrp.production.workcenter.line').action_done(cr,uid,[workcenter_line.id]) return super(mrp_production,self).action_production_end(cr,uid,ids) def action_cancel(self, cr, uid, ids): obj=self.browse(cr,uid,ids)[0] for workcenter_line in obj.workcenter_lines: tmp=self.pool.get('mrp.production.workcenter.line').action_cancel(cr,uid,[workcenter_line.id]) return super(mrp_production,self).action_cancel(cr,uid,ids) def _compute_planned_workcenter(self, cr, uid, ids, context={}, mini=False): dt_end = DateTime.now() for po in self.browse(cr, uid, ids, context=context): dt_end = DateTime.strptime(po.date_start or po.date_planned, '%Y-%m-%d %H:%M:%S') if not po.date_start: self.write(cr, uid, [po.id], { 'date_start': po.date_planned }, context=context, update=False) old = None for wci in range(len(po.workcenter_lines)): wc = po.workcenter_lines[wci] if (old is None) or (wc.sequence>old): dt = dt_end if context.get('__last_update'): del context['__last_update'] if (wc.date_planneddt): if l.production_id.state not in ('done','cancel'): for wc in l.production_id.workcenter_lines: i = self.pool.get('hr.timesheet.group').interval_min_get( cr, uid, wc.workcenter_id.timesheet_id.id or False, dt, wc.hour or 0.0 ) dt = i[0][0] if l.production_id.date_start>dt.strftime('%Y-%m-%d %H:%M:%S'): self.write(cr, uid, [l.production_id.id], {'date_start':dt.strftime('%Y-%m-%d %H:%M:%S')}, mini=True) return True def _move_futur(self, cr, uid, ids, context={}): for po in self.browse(cr, uid, ids, context): if po.allow_reorder: continue for line in po.move_created_ids: l = line while l.move_dest_id: l = l.move_dest_id if l.state in ('done','cancel','draft'): break if l.production_id.state in ('done','cancel'): break if l.production_id and (l.production_id.date_start