~jgrandguillaume-c2c/openobject-addons/multi-company-cost-price

« back to all changes in this revision

Viewing changes to mrp/mrp.py

  • Committer: Joël Grand-Guillaume
  • Date: 2010-04-08 09:00:10 UTC
  • mfrom: (2533.3.664)
  • Revision ID: joel.grandguillaume@camptocamp.com-20100408090010-c0pqjan341s18bxs
[MRG] Merge from last trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#
20
20
##############################################################################
21
21
 
 
22
from mx import DateTime
22
23
from osv import fields
23
24
from osv import osv
 
25
from tools.translate import _
24
26
import ir
25
 
 
26
27
import netsvc
27
28
import time
28
 
from mx import DateTime
29
 
from tools.translate import _
30
29
 
31
30
#----------------------------------------------------------
32
31
# Work Centers
334
333
        return f
335
334
    return round(f / r) * r
336
335
 
 
336
class many2many_domain(fields.many2many):
 
337
    def set(self, cr, obj, id, name, values, user=None, context=None):
 
338
        if not values:
 
339
            return
 
340
        return super(many2many_domain, self).set(cr, obj, id, name, values, user=user,
 
341
                context=context)
 
342
 
 
343
    def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
 
344
        if not context:
 
345
            context = {}
 
346
        res = {}
 
347
        move_obj = obj.pool.get('stock.move')
 
348
        for prod in obj.browse(cr, user, ids, context=context):
 
349
            cr.execute("SELECT move_id from mrp_production_move_ids where\
 
350
                production_id=%s" % (prod.id))
 
351
            m_ids = map(lambda x: x[0], cr.fetchall())
 
352
            final = move_obj.search(cr, user, self._domain + [('id', 'in', tuple(m_ids))])
 
353
            res[prod.id] = final
 
354
        return res
 
355
 
 
356
class one2many_domain(fields.one2many):
 
357
    def set(self, cr, obj, id, field, values, user=None, context=None):
 
358
        if not values:
 
359
            return
 
360
        return super(one2many_domain, self).set(cr, obj, id, field, values, 
 
361
                                            user=user, context=context)
 
362
 
 
363
    def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
 
364
        if not context:
 
365
            context = {}
 
366
        res = {}
 
367
        move_obj = obj.pool.get('stock.move')
 
368
        for prod in obj.browse(cr, user, ids, context=context):
 
369
            cr.execute("SELECT id from stock_move where production_id=%s" % (prod.id))
 
370
            m_ids = map(lambda x: x[0], cr.fetchall())
 
371
            final = move_obj.search(cr, user, self._domain + [('id', 'in', tuple(m_ids))])
 
372
            res[prod.id] = final
 
373
        return res
 
374
 
337
375
class mrp_production(osv.osv):
338
376
    _name = 'mrp.production'
339
377
    _description = 'Production'
420
458
        'picking_id': fields.many2one('stock.picking', 'Picking list', readonly=True,
421
459
            help="This is the internal picking list that brings the finished product to the production plan"),
422
460
        'move_prod_id': fields.many2one('stock.move', 'Move product', readonly=True),
423
 
        'move_lines': fields.many2many('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products Consummed'),
424
 
 
425
 
        'move_created_ids': fields.one2many('stock.move', 'production_id', 'Moves Created'),
 
461
        'move_lines': many2many_domain('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Products to Consumme', domain=[('state','not in', ('done', 'cancel'))]),
 
462
        'move_lines2': many2many_domain('stock.move', 'mrp_production_move_ids', 'production_id', 'move_id', 'Consummed Products', domain=[('state','in', ('done', 'cancel'))]),
 
463
        'move_created_ids': one2many_domain('stock.move', 'production_id', 'Moves Created', domain=[('state','not in', ('done', 'cancel'))]),
 
464
        'move_created_ids2': one2many_domain('stock.move', 'production_id', 'Moves Created', domain=[('state','in', ('done', 'cancel'))]),
426
465
        'product_lines': fields.one2many('mrp.production.product.line', 'production_id', 'Scheduled goods'),
427
466
        'workcenter_lines': fields.one2many('mrp.production.workcenter.line', 'production_id', 'Work Centers Utilisation'),
428
467
        '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,
542
581
                        {'location_id':production.location_dest_id.id})
543
582
        return True
544
583
 
545
 
    #TODO Review materials in function in_prod and prod_end.
546
584
    def action_production_end(self, cr, uid, ids):
547
 
#        move_ids = []
548
585
        for production in self.browse(cr, uid, ids):
549
 
            for res in production.move_lines:
550
 
                for move in production.move_created_ids:
551
 
                    #XXX must use the orm
552
 
                    cr.execute('INSERT INTO stock_move_history_ids \
553
 
                            (parent_id, child_id) VALUES (%s,%s)',
554
 
                            (res.id, move.id))
555
 
#                move_ids.append(res.id)
556
 
            vals= {'state':'confirmed'}
557
 
            new_moves = [x.id for x in production.move_created_ids]
558
 
            self.pool.get('stock.move').write(cr, uid, new_moves, vals)
559
 
            if not production.date_finnished:
560
 
                self.write(cr, uid, [production.id],
561
 
                        {'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')})
562
 
            self.pool.get('stock.move').check_assign(cr, uid, new_moves)
563
 
            self.pool.get('stock.move').action_done(cr, uid, new_moves)
564
586
            self._costs_generate(cr, uid, production)
565
 
#        self.pool.get('stock.move').action_done(cr, uid, move_ids)
566
 
        self.write(cr,  uid, ids, {'state': 'done'})
 
587
        return self.write(cr,  uid, ids, {'state': 'done', 'date_finnished': time.strftime('%Y-%m-%d %H:%M:%S')})
 
588
 
 
589
    def test_production_done(self, cr, uid, ids):
 
590
        res = True
 
591
        for production in self.browse(cr, uid, ids):            
 
592
            if production.move_lines:                
 
593
               res = False
 
594
 
 
595
            if production.move_created_ids:                
 
596
               res = False        
 
597
        return res
 
598
 
 
599
    def do_produce(self, cr, uid, production_id, production_qty, production_mode, context=None):
 
600
        stock_mov_obj = self.pool.get('stock.move')
 
601
        production = self.browse(cr, uid, production_id)
 
602
        
 
603
        raw_product_todo = []
 
604
        final_product_todo = []        
 
605
        
 
606
        if production_mode in ['consume','consume_produce']:
 
607
            consumed_products = {}
 
608
            produced_qty = 0
 
609
            for consumed_product in production.move_lines2:
 
610
                if consumed_product.scraped:
 
611
                    continue
 
612
                if not consumed_products.get(consumed_product.product_id.id, False):
 
613
                    consumed_products[consumed_product.product_id.id] = 0
 
614
                consumed_products[consumed_product.product_id.id] += consumed_product.product_qty
 
615
            
 
616
            for produced_product in production.move_created_ids2:
 
617
                if produced_product.scraped:
 
618
                    continue
 
619
                produced_qty += produced_product.product_qty
 
620
 
 
621
            for raw_product in production.move_lines:                
 
622
                consumed_qty = consumed_products.get(raw_product.product_id.id, 0)                
 
623
                consumed_qty -= produced_qty                            
 
624
                rest_qty = production_qty - consumed_qty 
 
625
                if rest_qty > production.product_qty:
 
626
                   rest_qty = production.product_qty            
 
627
                if rest_qty > 0:
 
628
                    stock_mov_obj.action_consume(cr, uid, [raw_product.id], rest_qty, production.location_src_id.id, context=context)
 
629
 
 
630
        if production_mode == 'consume_produce':
 
631
            vals = {'state':'confirmed'}
 
632
            final_product_todo = [x.id for x in production.move_created_ids]
 
633
            stock_mov_obj.write(cr, uid, final_product_todo, vals)
 
634
            produced_products = {}
 
635
            for produced_product in production.move_created_ids2:
 
636
                if produced_product.scraped:
 
637
                    continue
 
638
                if not produced_products.get(produced_product.product_id.id, False):
 
639
                    produced_products[produced_product.product_id.id] = 0
 
640
                produced_products[produced_product.product_id.id] += produced_product.product_qty
 
641
 
 
642
            for produce_product in production.move_created_ids:                
 
643
                produced_qty = produced_products.get(produce_product.product_id.id, 0)                            
 
644
                rest_qty = production.product_qty - produced_qty
 
645
                if rest_qty <= production_qty:
 
646
                   production_qty = rest_qty 
 
647
                if rest_qty > 0 :
 
648
                    stock_mov_obj.action_consume(cr, uid, [produce_product.id], production_qty, production.location_dest_id.id, context=context)            
 
649
        
 
650
        
 
651
        for raw_product in production.move_lines2: 
 
652
            new_parent_ids = []           
 
653
            parent_move_ids = [x.id for x in raw_product.move_history_ids]
 
654
            for final_product in production.move_created_ids2:
 
655
                if final_product.id not in parent_move_ids:
 
656
                    new_parent_ids.append(final_product.id)
 
657
            for new_parent_id in new_parent_ids:
 
658
                stock_mov_obj.write(cr, uid, [raw_product.id], {'move_history_ids':[(4,new_parent_id)]})
 
659
 
 
660
        wf_service = netsvc.LocalService("workflow")
 
661
        wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_produce_done', cr)
567
662
        return True
568
663
 
569
664
    def _costs_generate(self, cr, uid, production):
599
694
        return amount
600
695
 
601
696
    def action_in_production(self, cr, uid, ids):
602
 
        move_ids = []
603
 
        for production in self.browse(cr, uid, ids):
604
 
            for res in production.move_lines:
605
 
                move_ids.append(res.id)
606
 
            if not production.date_start:
607
 
                self.write(cr, uid, [production.id],
608
 
                        {'date_start': time.strftime('%Y-%m-%d %H:%M:%S')})
609
 
        self.pool.get('stock.move').action_done(cr, uid, move_ids)
610
 
        self.write(cr, uid, ids, {'state': 'in_production'})
 
697
        move_ids = []        
 
698
        self.write(cr, uid, ids, {'state': 'in_production','date_start':time.strftime('%Y-%m-%d %H:%M:%S')})
611
699
        return True
612
700
 
613
701
    def test_if_product(self, cr, uid, ids):
729
817
 
730
818
mrp_production()
731
819
 
732
 
 
733
 
class stock_move(osv.osv):
734
 
    _name = 'stock.move'
735
 
    _inherit = 'stock.move'
736
 
    _columns = {
737
 
        'production_id': fields.many2one('mrp.production', 'Production', select=True),
738
 
    }
739
 
stock_move()
740
 
 
741
820
class mrp_production_workcenter_line(osv.osv):
742
821
    _name = 'mrp.production.workcenter.line'
743
822
    _description = 'Work Orders'
783
862
    _description = "Procurement"
784
863
    _order = 'priority,date_planned'
785
864
    _columns = {
786
 
        'name': fields.char('Name', size=64, required=True, help='Requisition name.'),
 
865
        'name': fields.char('Reason', size=64, required=True, help='Requisition name.'),
787
866
        'origin': fields.char('Source Document', size=64,
788
867
            help="Reference of the document that created this Requisition.\n"
789
868
            "This is automatically completed by Open ERP."),
1175
1254
        self._procure_orderpoint_confirm(cr, uid, automatic=automatic,\
1176
1255
                use_new_cursor=use_new_cursor, context=context)
1177
1256
mrp_procurement()
1178
 
 
1179
 
 
1180
 
class stock_warehouse_orderpoint(osv.osv):
1181
 
    _name = "stock.warehouse.orderpoint"
1182
 
    _description = "Orderpoint minimum rule"
1183
 
    _columns = {
1184
 
        'name': fields.char('Name', size=32, required=True),
1185
 
        'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the orderpoint without removing it."),
1186
 
        'logic': fields.selection([('max','Order to Max'),('price','Best price (not yet active!)')], 'Reordering Mode', required=True),
1187
 
        'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True),
1188
 
        'location_id': fields.many2one('stock.location', 'Location', required=True),
1189
 
        'product_id': fields.many2one('product.product', 'Product', required=True, domain=[('type','=','product')]),
1190
 
        'product_uom': fields.many2one('product.uom', 'Product UOM', required=True ),
1191
 
        'product_min_qty': fields.float('Min Quantity', required=True,
1192
 
            help="When the virtual stock goes belong the Min Quantity, Open ERP generates "\
1193
 
            "a requisition to bring the virtual stock to the Max Quantity."),
1194
 
        'product_max_qty': fields.float('Max Quantity', required=True,
1195
 
            help="When the virtual stock goes belong the Min Quantity, Open ERP generates "\
1196
 
            "a requisition to bring the virtual stock to the Max Quantity."),
1197
 
        'qty_multiple': fields.integer('Qty Multiple', required=True,
1198
 
            help="The requisition quantity will by rounded up to this multiple."),
1199
 
        'procurement_id': fields.many2one('mrp.procurement', 'Purchase Order'),
1200
 
        'company_id': fields.many2one('res.company','Company',required=True),
1201
 
    }
1202
 
    _defaults = {
1203
 
        'active': lambda *a: 1,
1204
 
        'logic': lambda *a: 'max',
1205
 
        'qty_multiple': lambda *a: 1,
1206
 
        'name': lambda x,y,z,c: x.pool.get('ir.sequence').get(y,z,'mrp.warehouse.orderpoint') or '',
1207
 
        'product_uom': lambda sel, cr, uid, context: context.get('product_uom', False),
1208
 
        'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.warehouse.orderpoint', context=c)
1209
 
    }
1210
 
    def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, context={}):
1211
 
        if warehouse_id:
1212
 
            w=self.pool.get('stock.warehouse').browse(cr,uid,warehouse_id, context)
1213
 
            v = {'location_id':w.lot_stock_id.id}
1214
 
            return {'value': v}
1215
 
        return {}
1216
 
    def onchange_product_id(self, cr, uid, ids, product_id, context={}):
1217
 
        if product_id:
1218
 
            prod=self.pool.get('product.product').browse(cr,uid,product_id)
1219
 
            v = {'product_uom':prod.uom_id.id}
1220
 
            return {'value': v}
1221
 
        return {}
1222
 
    def copy(self, cr, uid, id, default=None,context={}):
1223
 
        if not default:
1224
 
            default = {}
1225
 
        default.update({
1226
 
            'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.warehouse.orderpoint') or '',
1227
 
        })
1228
 
        return super(stock_warehouse_orderpoint, self).copy(cr, uid, id, default, context)
1229
 
stock_warehouse_orderpoint()
1230
 
 
1231
 
 
1232
 
class StockMove(osv.osv):
1233
 
    _inherit = 'stock.move'
1234
 
    _columns = {
1235
 
        'procurements': fields.one2many('mrp.procurement', 'move_id', 'Requisitions'),
1236
 
    }
1237
 
    def copy(self, cr, uid, id, default=None, context=None):
1238
 
        default = default or {}
1239
 
        default['procurements'] = []
1240
 
        return super(StockMove, self).copy(cr, uid, id, default, context)
1241
 
 
1242
 
    def _action_explode(self, cr, uid, move, context={}):
1243
 
        if move.product_id.supply_method=='produce' and move.product_id.procure_method=='make_to_order':
1244
 
            bis = self.pool.get('mrp.bom').search(cr, uid, [
1245
 
                ('product_id','=',move.product_id.id),
1246
 
                ('bom_id','=',False),
1247
 
                ('type','=','phantom')])
1248
 
            if bis:
1249
 
                factor = move.product_qty
1250
 
                bom_point = self.pool.get('mrp.bom').browse(cr, uid, bis[0])
1251
 
                res = self.pool.get('mrp.bom')._bom_explode(cr, uid, bom_point, factor, [])
1252
 
                dest = move.product_id.product_tmpl_id.property_stock_production.id
1253
 
                state = 'confirmed'
1254
 
                if move.state=='assigned':
1255
 
                    state='assigned'
1256
 
                for line in res[0]:
1257
 
                    print 'Line :',line
1258
 
                    valdef = {
1259
 
                        'picking_id': move.picking_id.id,
1260
 
                        'product_id': line['product_id'],
1261
 
                        'product_uom': line['product_uom'],
1262
 
                        'product_qty': line['product_qty'],
1263
 
                        'product_uos': line['product_uos'],
1264
 
                        'product_uos_qty': line['product_uos_qty'],
1265
 
                        'move_dest_id': move.id,
1266
 
                        'state': state,
1267
 
                        'name': line['name'],
1268
 
                        'location_dest_id': dest,
1269
 
                        'move_history_ids': [(6,0,[move.id])],
1270
 
                        'move_history_ids2': [(6,0,[])],
1271
 
                        'procurements': [],
1272
 
                    }
1273
 
                    mid = self.pool.get('stock.move').copy(cr, uid, move.id, default=valdef)
1274
 
                    prodobj = self.pool.get('product.product').browse(cr, uid, line['product_id'], context=context)
1275
 
                    proc_id = self.pool.get('mrp.procurement').create(cr, uid, {
1276
 
                        'name': (move.picking_id.origin or ''),
1277
 
                        'origin': (move.picking_id.origin or ''),
1278
 
                        'date_planned': move.date_planned,
1279
 
                        'product_id': line['product_id'],
1280
 
                        'product_qty': line['product_qty'],
1281
 
                        'product_uom': line['product_uom'],
1282
 
                        'product_uos_qty': line['product_uos'] and line['product_uos_qty'] or False,
1283
 
                        'product_uos':  line['product_uos'],
1284
 
                        'location_id': move.location_id.id,
1285
 
                        'procure_method': prodobj.procure_method,
1286
 
                        'move_id': mid,
1287
 
                        'company_id': line['company_id'],
1288
 
                    })
1289
 
                    wf_service = netsvc.LocalService("workflow")
1290
 
                    wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr)
1291
 
                self.pool.get('stock.move').write(cr, uid, [move.id], {
1292
 
                    'location_id': move.location_dest_id.id,
1293
 
                    'auto_validate': True,
1294
 
                    'picking_id': False,
1295
 
                    'location_id': dest,
1296
 
                    'state': 'waiting'
1297
 
                })
1298
 
                for m in self.pool.get('mrp.procurement').search(cr, uid, [('move_id','=',move.id)], context):
1299
 
                    wf_service = netsvc.LocalService("workflow")
1300
 
                    wf_service.trg_validate(uid, 'mrp.procurement', m, 'button_wait_done', cr)
1301
 
        return True
1302
 
StockMove()
1303
 
 
1304
 
 
1305
 
class StockPicking(osv.osv):
1306
 
    _inherit = 'stock.picking'
1307
 
 
1308
 
    def test_finnished(self, cursor, user, ids):
1309
 
        wf_service = netsvc.LocalService("workflow")
1310
 
        res = super(StockPicking, self).test_finnished(cursor, user, ids)
1311
 
        for picking in self.browse(cursor, user, ids):
1312
 
            for move in picking.move_lines:
1313
 
                if move.state == 'done' and move.procurements:
1314
 
                    for procurement in move.procurements:
1315
 
                        wf_service.trg_validate(user, 'mrp.procurement',
1316
 
                                procurement.id, 'button_check', cursor)
1317
 
        return res
1318
 
 
1319
 
    #
1320
 
    # Explode picking by replacing phantom BoMs
1321
 
    #
1322
 
    def action_explode(self, cr, uid, picks, *args):
1323
 
        for move in self.pool.get('stock.move').browse(cr, uid, picks):
1324
 
            self.pool.get('stock.move')._action_explode(cr, uid, move)
1325
 
        return picks
1326
 
 
1327
 
StockPicking()
1328
 
 
1329
1257
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1330
1258