335
334
return round(f / r) * r
336
class many2many_domain(fields.many2many):
337
def set(self, cr, obj, id, name, values, user=None, context=None):
340
return super(many2many_domain, self).set(cr, obj, id, name, values, user=user,
343
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
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))])
356
class one2many_domain(fields.one2many):
357
def set(self, cr, obj, id, field, values, user=None, context=None):
360
return super(one2many_domain, self).set(cr, obj, id, field, values,
361
user=user, context=context)
363
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
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))])
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'),
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})
545
#TODO Review materials in function in_prod and prod_end.
546
584
def action_production_end(self, cr, uid, 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)',
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')})
589
def test_production_done(self, cr, uid, ids):
591
for production in self.browse(cr, uid, ids):
592
if production.move_lines:
595
if production.move_created_ids:
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)
603
raw_product_todo = []
604
final_product_todo = []
606
if production_mode in ['consume','consume_produce']:
607
consumed_products = {}
609
for consumed_product in production.move_lines2:
610
if consumed_product.scraped:
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
616
for produced_product in production.move_created_ids2:
617
if produced_product.scraped:
619
produced_qty += produced_product.product_qty
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
628
stock_mov_obj.action_consume(cr, uid, [raw_product.id], rest_qty, production.location_src_id.id, context=context)
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:
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
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
648
stock_mov_obj.action_consume(cr, uid, [produce_product.id], production_qty, production.location_dest_id.id, context=context)
651
for raw_product in production.move_lines2:
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)]})
660
wf_service = netsvc.LocalService("workflow")
661
wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_produce_done', cr)
569
664
def _costs_generate(self, cr, uid, production):
1175
1254
self._procure_orderpoint_confirm(cr, uid, automatic=automatic,\
1176
1255
use_new_cursor=use_new_cursor, context=context)
1177
1256
mrp_procurement()
1180
class stock_warehouse_orderpoint(osv.osv):
1181
_name = "stock.warehouse.orderpoint"
1182
_description = "Orderpoint minimum rule"
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),
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)
1210
def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, context={}):
1212
w=self.pool.get('stock.warehouse').browse(cr,uid,warehouse_id, context)
1213
v = {'location_id':w.lot_stock_id.id}
1216
def onchange_product_id(self, cr, uid, ids, product_id, context={}):
1218
prod=self.pool.get('product.product').browse(cr,uid,product_id)
1219
v = {'product_uom':prod.uom_id.id}
1222
def copy(self, cr, uid, id, default=None,context={}):
1226
'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.warehouse.orderpoint') or '',
1228
return super(stock_warehouse_orderpoint, self).copy(cr, uid, id, default, context)
1229
stock_warehouse_orderpoint()
1232
class StockMove(osv.osv):
1233
_inherit = 'stock.move'
1235
'procurements': fields.one2many('mrp.procurement', 'move_id', 'Requisitions'),
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)
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')])
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
1254
if move.state=='assigned':
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,
1267
'name': line['name'],
1268
'location_dest_id': dest,
1269
'move_history_ids': [(6,0,[move.id])],
1270
'move_history_ids2': [(6,0,[])],
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,
1287
'company_id': line['company_id'],
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,
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)
1305
class StockPicking(osv.osv):
1306
_inherit = 'stock.picking'
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)
1320
# Explode picking by replacing phantom BoMs
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)
1329
1257
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: