From 14dfea38ab12f8b690b162731f76d1a15758a593 Mon Sep 17 00:00:00 2001 From: "vra (Tiny)" Date: Mon, 1 Jun 2009 09:46:56 +0530 Subject: [PATCH 1/8] Update the branch with stable addons. bzr revid: vinusoft85@gmail.com-20090601041656-zi2ujghj6mr1690r --- addons/hr/hr.py | 78 ++++--- addons/mrp/mrp.py | 17 +- addons/mrp/mrp_view.xml | 4 +- addons/mrp_operations/mrp_operations.py | 211 +++++++++++++++--- addons/mrp_operations/mrp_operations_view.xml | 95 ++++++-- 5 files changed, 309 insertions(+), 96 deletions(-) diff --git a/addons/hr/hr.py b/addons/hr/hr.py index 5489735db29..3fe64ea6bba 100644 --- a/addons/hr/hr.py +++ b/addons/hr/hr.py @@ -22,6 +22,7 @@ from mx import DateTime import time +import math from osv import fields, osv from tools.translate import _ @@ -34,50 +35,57 @@ class hr_timesheet_group(osv.osv): 'timesheet_id' : fields.one2many('hr.timesheet', 'tgroup_id', 'Working Time'), 'manager' : fields.many2one('res.users', 'Workgroup manager'), } - # - # TODO: improve; very slow ! - # bug if transition to another period - # + def interval_min_get(self, cr, uid, id, dt_from, hours): + if not id: + return [(dt_from-DateTime.RelativeDateTime(hours=int(hours)*3), dt_from)] + todo = hours + cycle = 0 + result = [] + maxrecur = 100 + current_hour = dt_from.hour + while (todo>0) and maxrecur: + cr.execute("select hour_from,hour_to from hr_timesheet where dayofweek='%s' and tgroup_id=%s order by hour_from desc", (dt_from.day_of_week,id)) + for (hour_from,hour_to) in cr.fetchall(): + if (hour_from0): + m = min(hour_to, current_hour) + if (m-hour_from)>todo: + hour_from = m-todo + d1 = DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_from)),int((hour_from%1) * 60)) + d2 = DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) + result.append((d1, d2)) + current_hour = hour_from + todo -= (m-hour_from) + dt_from -= DateTime.RelativeDateTime(days=1) + current_hour = 24 + maxrecur -= 1 + result.reverse() + return result + def interval_get(self, cr, uid, id, dt_from, hours, byday=True): if not id: return [(dt_from,dt_from+DateTime.RelativeDateTime(hours=int(hours)*3))] todo = hours cycle = 0 result = [] - while todo>0: + maxrecur = 100 + current_hour = dt_from.hour + while (todo>0) and maxrecur: cr.execute("select hour_from,hour_to from hr_timesheet where dayofweek='%s' and tgroup_id=%s order by hour_from", (dt_from.day_of_week,id)) for (hour_from,hour_to) in cr.fetchall(): - - import math - - hour_from = '%02d:%02d' % (math.floor(abs(hour_from)),round(abs(hour_from)%1+0.01,2) * 60) - hour_to = '%02d:%02d' % (math.floor(abs(hour_to)),round(abs(hour_to)%1+0.01,2) * 60) - - h1,m1 = map(int,hour_from.split(':')) - h2,m2 = map(int,hour_to.split(':')) - d1 = DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,h1,m1) - d2 = DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,h2,m2) - if dt_from7 and todo==hours: - return [(dt_from,dt_from+DateTime.RelativeDateTime(hours=hours*3))] - if byday: - i = 1 - while icurrent_hour) and (todo>0): + m = max(hour_from, current_hour) + if (hour_to-m)>todo: + hour_to = m+todo + d1 = DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(m)),int((m%1) * 60)) + d2 = DateTime.DateTime(dt_from.year,dt_from.month,dt_from.day,int(math.floor(hour_to)),int((hour_to%1) * 60)) + result.append((d1, d2)) + current_hour = hour_to + todo -= (hour_to - m) + dt_from += DateTime.RelativeDateTime(days=1) + current_hour = 0 + maxrecur -= 1 return result + hr_timesheet_group() diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 726b7c0325f..e1f02ec39a6 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -380,6 +380,12 @@ class mrp_production(osv.osv): result[prod.id]['cycle_total'] += wc.cycle return result + 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 + return result + def _production_date(self, cr, uid, ids, prop, unknow_none, context={}): result = {} for prod in self.browse(cr, uid, ids, context=context): @@ -408,7 +414,8 @@ class mrp_production(osv.osv): 'location_dest_id': fields.many2one('stock.location', 'Finished Products Location', required=True, help="Location where the system will stock the finished products."), - 'date_planned_date': fields.function(_production_date, method=True, type='date', string='Planned Date'), + 'date_planned_end': fields.function(_production_date_end, method=True, type='date', string='Scheduled End'), + 'date_planned_date': fields.function(_production_date, method=True, type='date', string='Scheduled Date'), 'date_planned': fields.datetime('Scheduled date', required=True, select=1), 'date_start': fields.datetime('Start Date'), 'date_finnished': fields.datetime('End Date'), @@ -456,7 +463,8 @@ class mrp_production(osv.osv): default.update({ 'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.production'), 'move_lines' : [], - 'move_created_ids': [] + 'move_created_ids': [], + 'state': 'draft' }) return super(mrp_production, self).copy(cr, uid, id, default, context) @@ -722,9 +730,10 @@ stock_move() class mrp_production_workcenter_line(osv.osv): _name = 'mrp.production.workcenter.line' - _description = 'Production workcenters used' + _description = 'Work Orders' + _order = 'sequence' _columns = { - 'name': fields.char('Name', size=64, required=True), + 'name': fields.char('Work Order', size=64, required=True), 'workcenter_id': fields.many2one('mrp.workcenter', 'Workcenter', required=True), 'cycle': fields.float('Nbr of cycle', digits=(16,2)), 'hour': fields.float('Nbr of hour', digits=(16,2)), diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index c2f8d94eaac..5ae97154a42 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -409,9 +409,9 @@ mrp.production gantt - + - + diff --git a/addons/mrp_operations/mrp_operations.py b/addons/mrp_operations/mrp_operations.py index 94a265c6bfb..94f1460ca1c 100644 --- a/addons/mrp_operations/mrp_operations.py +++ b/addons/mrp_operations/mrp_operations.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved +# dmr Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved # $Id$ # # This program is free software: you can redistribute it and/or modify @@ -39,22 +39,53 @@ from tools.translate import _ # 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): + 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' _columns = { 'state': fields.selection([('draft','Draft'),('startworking', 'In Progress'),('pause','Pause'),('cancel','Canceled'),('done','Finished')],'Status', readonly=True), - 'date_planned': fields.related('production_id', 'date_planned', type='datetime', string='Date Planned'), + '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.char('Delay',size=128,help="This is delay between operation start and stop in this workcenter",readonly=True), - 'production_state':fields.related('production_id','state',type='char',string='Prod.State'), - 'product':fields.related('production_id','product_id',type='many2one',relation='product.product',string='Product'), - 'qty':fields.related('production_id','product_qty',type='float',string='Qty'), - 'uom':fields.related('production_id','product_uom',type='many2one',relation='product.uom',string='UOM'), + '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 Days 0 hrs and 0 mins' + 'delay': lambda *a: 0.0 } def modify_production_order_state(self,cr,uid,ids,action): @@ -82,17 +113,28 @@ class mrp_production_workcenter_line(osv.osv): 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'}) + 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'}) + 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 @@ -111,9 +153,18 @@ class mrp_production_workcenter_line(osv.osv): mrp_production_workcenter_line() class mrp_production(osv.osv): - _name = 'mrp.production' _inherit = 'mrp.production' - _description = '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] @@ -127,6 +178,108 @@ class mrp_production(osv.osv): 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=60: - m+=1 - s=0 - if m>=60: - h+=1 - m=0 - if h>=24: - days+=1 - h=0 - delay=str(days) +" Days "+ str(h) + " hrs and " + str(m)+ " mins" - return delay + a = datetime.datetime.strptime(time_lst[i-1],'%Y:%m:%d %H:%M:%S') + b = datetime.datetime.strptime(time_lst[i],'%Y:%m:%d %H:%M:%S') + diff += (b-a).days * 24 + diff += (b-a).seconds / (60*60) + return diff def check_operation(self,cr,uid,vals): code_ids=self.pool.get('mrp_operations.operation.code').search(cr,uid,[('id','=',vals['code_id'])]) @@ -300,8 +439,8 @@ class mrp_operations_operation(osv.osv): 'order_date': fields.function(_get_order_date,method=True,string='Order Date',type='date',store={'mrp.production':(_order_date_search_production,['date_planned'], 10)}), } _defaults={ - 'date_start': lambda *a:DateTime.now().strftime('%Y-%m-%d %H:%M:%S') - } + 'date_start': lambda *a:DateTime.now().strftime('%Y-%m-%d %H:%M:%S') + } mrp_operations_operation() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mrp_operations/mrp_operations_view.xml b/addons/mrp_operations/mrp_operations_view.xml index 6d0ac9bcee3..7f248929dd5 100644 --- a/addons/mrp_operations/mrp_operations_view.xml +++ b/addons/mrp_operations/mrp_operations_view.xml @@ -10,6 +10,7 @@ + @@ -31,22 +32,52 @@
- - - - - - - - - -