481
486
\n* The \'Available\' state is set automatically when the products are ready to be moved.\
482
487
\n* The \'Waiting\' state is used in MTO moves when a movement is waiting for another one.'),
483
488
'min_date': fields.function(get_min_max_date, fnct_inv=_set_minimum_date, multi="min_max_date",
484
method=True, store=True, type='datetime', string='Planned Date', select=1, help="Planned date for Picking. Default it takes current date"),
485
'date': fields.datetime('Date Order', help="Date of Order"),
489
method=True, store=True, type='datetime', string='Expected Date', select=1, help="Expected date for Picking. Default it takes current date"),
490
'date': fields.datetime('Order Date', help="Date of Order"),
486
491
'date_done': fields.datetime('Date Done', help="Date of completion"),
487
492
'max_date': fields.function(get_min_max_date, fnct_inv=_set_maximum_date, multi="min_max_date",
488
method=True, store=True, type='datetime', string='Max. Planned Date', select=2),
493
method=True, store=True, type='datetime', string='Max. Expected Date', select=2),
489
494
'move_lines': fields.one2many('stock.move', 'picking_id', 'Entry lines', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
490
495
'auto_picking': fields.boolean('Auto-Picking'),
491
496
'address_id': fields.many2one('res.partner.address', 'Partner', help="Address of partner"),
932
941
stock_production_lot()
934
class stock_split_production_lots(osv.osv_memory):
935
_name = "stock.split.production.lots"
936
_description = "Split Production Lots"
938
def _quantity_default_get(self, cr, uid, object=False, field=False, context=None):
939
cr.execute("select %s from %s where id=%s" %(field,object,context.get('active_id')))
940
res = cr.fetchone()[0]
944
'name': fields.char('Lot Number/Prefix', size=64, required=True),
945
'qty': fields.float('Total Quantity'),
946
'action': fields.selection([('split','Split'),('keepinone','Keep in one lot')],'Action'),
949
'qty': lambda self,cr,uid,c: self.pool.get('stock.split.production.lots')._quantity_default_get(cr, uid, 'stock_move', 'product_qty',context=c) or 1,
952
def split_lines(self, cr, uid, ids, context={}):
953
data = self.read(cr, uid, ids[0])
954
prodlot_obj = self.pool.get('stock.production.lot')
955
move_obj = self.pool.get('stock.move')
956
move_browse = move_obj.browse(cr, uid, context['active_id'])
958
quantity = data['qty']
959
if quantity <= 0 or move_browse.product_qty == 0:
961
uos_qty = quantity/move_browse.product_qty*move_browse.product_uos_qty
963
quantity_rest = move_browse.product_qty%quantity
964
uos_qty_rest = quantity_rest/move_browse.product_qty*move_browse.product_uos_qty
967
'product_qty': quantity,
968
'product_uos_qty': uos_qty,
972
for idx in range(int(move_browse.product_qty//quantity)):
974
current_move = move_obj.copy(cr, uid, move_browse.id, {'state': move_browse.state})
975
new_move.append(current_move)
977
current_move = move_browse.id
978
new_prodlot = prodlot_obj.create(cr, uid, {'name': data['name'], 'ref': '%d'%idx}, {'product_id': move_browse.product_id.id})
979
update_val['prodlot_id'] = new_prodlot
980
move_obj.write(cr, uid, [current_move], update_val)
982
if quantity_rest > 0:
983
idx = int(move_browse.product_qty//quantity)
984
update_val['product_qty'] = quantity_rest
985
update_val['product_uos_qty'] = uos_qty_rest
987
current_move = move_obj.copy(cr, uid, move_browse.id, {'state': move_browse.state})
988
new_move.append(current_move)
990
current_move = move_browse.id
991
new_prodlot = prodlot_obj.create(cr, uid, {'name': data['name'], 'ref': '%d'%idx}, {'product_id': move_browse.product_id.id})
992
update_val['prodlot_id'] = new_prodlot
993
move_obj.write(cr, uid, [current_move], update_val)
997
stock_split_production_lots()
1000
943
class stock_production_lot_revision(osv.osv):
1001
944
_name = 'stock.production.lot.revision'
1002
945
_description = 'Production lot revisions'
1094
1037
help='When the stock move is created it is in the \'Draft\' state.\n After that it is set to \'Confirmed\' state.\n If stock is available state is set to \'Avaiable\'.\n When the picking it done the state is \'Done\'.\
1095
1038
\nThe state is \'Waiting\' if the move is waiting for another one.'),
1096
1039
'price_unit': fields.float('Unit Price',
1097
digits=(16, int(config['price_accuracy']))),
1040
digits_compute= dp.get_precision('Account')),
1098
1041
'company_id': fields.many2one('res.company', 'Company', required=True,select=1),
1099
1042
'partner_id': fields.related('picking_id','address_id','partner_id',type='many2one', relation="res.partner", string="Partner"),
1100
1043
'backorder_id': fields.related('picking_id','backorder_id',type='many2one', relation="stock.picking", string="Back Orders"),
1101
'origin': fields.related('picking_id','origin',type='char', size=64, relation="stock.picking", string="Source document"),
1044
'origin': fields.related('picking_id','origin',type='char', size=64, relation="stock.picking", string="Origin"),
1102
1045
'move_stock_return_history': fields.many2many('stock.move', 'stock_move_return_history', 'move_id', 'return_move_id', 'Move Return History',readonly=True),
1046
'scraped': fields.boolean('Scraped'),
1104
1048
_constraints = [
1105
1049
(_check_tracking,
1492
1444
raise osv.except_osv(_('UserError'),
1493
1445
_('You can only delete draft moves.'))
1494
1446
return super(stock_move, self).unlink(
1495
cr, uid, ids, context=context)
1447
cr, uid, ids, context=context)
1449
def _create_lot(self, cr, uid, ids, product_id, prefix=False):
1450
prodlot_obj = self.pool.get('stock.production.lot')
1451
ir_sequence_obj = self.pool.get('ir.sequence')
1452
sequence = ir_sequence_obj.get(cr, uid, 'stock.lot.serial')
1454
raise wizard.except_wizard(_('Error!'), _('No production sequence defined'))
1455
prodlot_id = prodlot_obj.create(cr, uid, {'name': sequence, 'prefix': prefix}, {'product_id': product_id})
1456
prodlot = prodlot_obj.browse(cr, uid, prodlot_id)
1457
ref = ','.join(map(lambda x:str(x),ids))
1459
ref = '%s, %s' % (prodlot.ref, ref)
1460
prodlot_obj.write(cr, uid, [prodlot_id], {'ref': ref})
1463
def action_scrap(self, cr, uid, ids, quantity, location_id, context=None):
1465
Move the scrap/damaged product into scrap location
1467
@ param cr: the database cursor
1468
@ param uid: the user id
1469
@ param ids: ids of stock move object to be scraped
1470
@ param quantity : specify scrap qty
1471
@ param location_id : specify scrap location
1472
@ param context: context arguments
1474
@ return: Scraped lines
1477
raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
1479
for move in self.browse(cr, uid, ids, context=context):
1480
move_qty = move.product_qty
1481
uos_qty = quantity / move_qty * move.product_uos_qty
1483
'product_qty': quantity,
1484
'product_uos_qty': uos_qty,
1485
'state': move.state,
1487
'location_dest_id': location_id
1489
new_move = self.copy(cr, uid, move.id, default_val)
1490
#self.write(cr, uid, [new_move], {'move_history_ids':[(4,move.id)]}) #TODO : to track scrap moves
1492
self.action_done(cr, uid, res)
1495
def action_split(self, cr, uid, ids, quantity, split_by_qty=1, prefix=False, with_lot=True, context=None):
1497
Split Stock Move lines into production lot which specified split by quantity.
1499
@ param cr: the database cursor
1500
@ param uid: the user id
1501
@ param ids: ids of stock move object to be splited
1502
@ param split_by_qty : specify split by qty
1503
@ param prefix : specify prefix of production lot
1504
@ param with_lot : if true, prodcution lot will assign for split line otherwise not.
1505
@ param context: context arguments
1507
@ return: splited move lines
1511
raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
1515
for move in self.browse(cr, uid, ids):
1516
if split_by_qty <= 0 or quantity == 0:
1519
uos_qty = split_by_qty / move.product_qty * move.product_uos_qty
1521
quantity_rest = quantity % split_by_qty
1522
uos_qty_rest = split_by_qty / move.product_qty * move.product_uos_qty
1525
'product_qty': split_by_qty,
1526
'product_uos_qty': uos_qty,
1528
for idx in range(int(quantity//split_by_qty)):
1529
if not idx and move.product_qty<=quantity:
1530
current_move = move.id
1532
current_move = self.copy(cr, uid, move.id, {'state': move.state})
1533
res.append(current_move)
1535
update_val['prodlot_id'] = self._create_lot(cr, uid, [current_move], move.product_id.id)
1537
self.write(cr, uid, [current_move], update_val)
1540
if quantity_rest > 0:
1541
idx = int(quantity//split_by_qty)
1542
update_val['product_qty'] = quantity_rest
1543
update_val['product_uos_qty'] = uos_qty_rest
1544
if not idx and move.product_qty<=quantity:
1545
current_move = move.id
1547
current_move = self.copy(cr, uid, move.id, {'state': move.state})
1549
res.append(current_move)
1553
update_val['prodlot_id'] = self._create_lot(cr, uid, [current_move], move.product_id.id)
1555
self.write(cr, uid, [current_move], update_val)
1558
def action_consume(self, cr, uid, ids, quantity, location_id=False, context=None):
1560
Consumed product with specific quatity from specific source location
1562
@ param cr: the database cursor
1563
@ param uid: the user id
1564
@ param ids: ids of stock move object to be consumed
1565
@ param quantity : specify consume quantity
1566
@ param location_id : specify source location
1567
@ param context: context arguments
1569
@ return: Consumed lines
1575
raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
1578
for move in self.browse(cr, uid, ids, context=context):
1579
move_qty = move.product_qty
1580
quantity_rest = move.product_qty
1582
quantity_rest -= quantity
1583
uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
1584
if quantity_rest <= 0:
1587
quantity = move.product_qty
1589
uos_qty = quantity / move_qty * move.product_uos_qty
1591
if quantity_rest > 0:
1593
'product_qty': quantity,
1594
'product_uos_qty': uos_qty,
1595
'state': move.state,
1596
'location_id': location_id
1598
if move.product_id.track_production and location_id:
1599
# IF product has checked track for production lot, move lines will be split by 1
1600
res += self.action_split(cr, uid, [move.id], quantity, split_by_qty=1, context=context)
1602
current_move = self.copy(cr, uid, move.id, default_val)
1603
res += [current_move]
1606
update_val['product_qty'] = quantity_rest
1607
update_val['product_uos_qty'] = uos_qty_rest
1608
self.write(cr, uid, [move.id], update_val)
1611
quantity_rest = quantity
1612
uos_qty_rest = uos_qty
1614
if move.product_id.track_production and location_id:
1615
res += self.split_lines(cr, uid, [move.id], quantity_rest, split_by_qty=1, context=context)
1619
'product_qty' : quantity_rest,
1620
'product_uos_qty' : uos_qty_rest,
1621
'location_id': location_id
1624
self.write(cr, uid, [move.id], update_val)
1626
self.action_done(cr, uid, res)