from tools import float_compare
import decimal_precision as dp
import logging
-
+_logger = logging.getLogger(__name__)
#----------------------------------------------------------
# Incoterms
# so we ROLLBACK to the SAVEPOINT to restore the transaction to its earlier
# state, we return False as if the products were not available, and log it:
cr.execute("ROLLBACK TO stock_location_product_reserve")
- logger = logging.getLogger('stock.location')
- logger.warn("Failed attempt to reserve %s x product %s, likely due to another transaction already in progress. Next attempt is likely to work. Detailed error available at DEBUG level.", product_qty, product_id)
- logger.debug("Trace of the failed product reservation attempt: ", exc_info=True)
+ _logger.warn("Failed attempt to reserve %s x product %s, likely due to another transaction already in progress. Next attempt is likely to work. Detailed error available at DEBUG level.", product_qty, product_id)
+ _logger.debug("Trace of the failed product reservation attempt: ", exc_info=True)
return False
# XXX TODO: rewrite this with one single query, possibly even the quantity conversion
return self.name_get(cr, user, ids, context)
def name_get(self, cr, uid, ids, context=None):
+ """Append the serial to the name"""
if not len(ids):
return []
- res = [(r['id'], r['name']+' ['+(r['serial'] or '')+']') for r in self.read(cr, uid, ids, ['name', 'serial'], context)]
+ res = [ (r['id'], r['serial'] and '%s [%s]' % (r['name'], r['serial'])
+ or r['name'] )
+ for r in self.read(cr, uid, ids, ['name', 'serial'],
+ context=context) ]
return res
def unlink(self, cr, uid, ids, context=None):
- raise osv.except_osv(_('Error'), _('You can not remove a lot line !'))
+ raise osv.except_osv(_('Error!'), _('You cannot remove a lot line.'))
def action_traceability(self, cr, uid, ids, context={}):
""" It traces the information of a product
#----------------------------------------------------------
# Stock Picking
#----------------------------------------------------------
-PICK_STATE = [
- ('draft', 'Draft'),
- ('auto', 'Waiting Another Operation'),
- ('confirmed', 'Waiting Availability'),
- ('assigned', 'Ready to Process'),
- ('done', 'Done'),
- ('cancel', 'Cancelled'),
-]
class stock_picking(osv.osv):
_name = "stock.picking"
_inherit = ['mail.thread']
res[pick]['min_date'] = dt1
res[pick]['max_date'] = dt2
return res
-
- def _tooltip_picking_state(self, state=None):
- # Update the tooltip of state field based on shipment type e.g: Delivery, Reception and Internal Transfer
- if state is None:
- state = PICK_STATE
- _tooltip_state_assigned = state.get('assigned', False)
- _tooltip_state_done = state.get('done', False)
- return _("* Draft: not confirmed yet and will not be scheduled until confirmed\n"\
- "* Waiting Another Operation: waiting for another move to proceed before it becomes automatically available (e.g. in Make-To-Order flows)\n"\
- "* Waiting Availability: still waiting for the availability of products\n"\
- "* %s: products reserved, simply waiting for confirmation.\n"\
- "* %s: has been processed, can't be modified or cancelled anymore\n"\
- "* Cancelled: has been cancelled, can't be confirmed anymore") % (_tooltip_state_assigned, _tooltip_state_done)
def create(self, cr, user, vals, context=None):
if ('name' not in vals) or (vals.get('name')=='/'):
_columns = {
'name': fields.char('Reference', size=64, select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
- 'origin': fields.char('Origin', size=64, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Reference of the document", select=True),
+ 'origin': fields.char('Source', size=64, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Reference of the document", select=True),
'backorder_id': fields.many2one('stock.picking', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
- 'type': fields.selection([('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal')], 'Shipping Type', required=True, select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Shipping type specify, goods coming in or going out."),
+ 'type': fields.selection([('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal')], 'Shipping Type', required=True, select=True, readonly=True, help="Shipping type specify, goods coming in or going out."),
'note': fields.text('Notes', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'stock_journal_id': fields.many2one('stock.journal','Stock Journal', select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'location_id': fields.many2one('stock.location', 'Location', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Keep empty if you produce at the location where the finished products are needed." \
"if you subcontract the manufacturing operations.", select=True),
'location_dest_id': fields.many2one('stock.location', 'Dest. Location', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Location where the system will stock the finished products.", select=True),
'move_type': fields.selection([('direct', 'Partial'), ('one', 'All at once')], 'Delivery Method', required=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="It specifies goods to be deliver partially or all at once"),
- 'state': fields.selection(PICK_STATE, 'State', readonly=True, select=True),
+ 'state': fields.selection([
+ ('draft', 'Draft'),
+ ('cancel', 'Cancelled'),
+ ('auto', 'Waiting Another Operation'),
+ ('confirmed', 'Waiting Availability'),
+ ('assigned', 'Ready to Transfer'),
+ ('done', 'Transferred'),
+ ], 'Status', readonly=True, select=True, help="""
+ * Draft: not confirmed yet and will not be scheduled until confirmed\n
+ * Waiting Another Operation: waiting for another move to proceed before it becomes automatically available (e.g. in Make-To-Order flows)\n
+ * Waiting Availability: still waiting for the availability of products\n
+ * Ready to Transfer: products reserved, simply waiting for confirmation.\n
+ * Transferred: has been processed, can't be modified or cancelled anymore\n
+ * Cancelled: has been cancelled, can't be confirmed anymore"""
+ ),
'min_date': fields.function(get_min_max_date, fnct_inv=_set_minimum_date, multi="min_max_date",
store=True, type='datetime', string='Scheduled Date', select=1, help="Scheduled date for the shipment to be processed"),
'date': fields.datetime('Order Date', help="Date of order", select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'max_date': fields.function(get_min_max_date, fnct_inv=_set_maximum_date, multi="min_max_date",
store=True, type='datetime', string='Max. Expected Date', select=2),
'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
- 'product_id': fields.related('move_lines','product_id', type='many2one', relation='product.product', string='Product',store=True),
+ 'product_id': fields.related('move_lines', 'product_id', type='many2one', relation='product.product', string='Product'),
'auto_picking': fields.boolean('Auto-Picking', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'partner_id': fields.many2one('res.partner', 'Partner', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'invoice_state': fields.selection([
'name': lambda self, cr, uid, context: '/',
'state': 'draft',
'move_type': 'direct',
- 'type': 'in',
+ 'type': 'internal',
'invoice_state': 'none',
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.picking', context=c)
_sql_constraints = [
('name_uniq', 'unique(name, company_id)', 'Reference must be unique per Company!'),
]
-
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- if context is None:
- context = {}
- mod_obj = self.pool.get('ir.model.data')
- # To get the right view of shipment based on type from stock move and Back order.
- if context.get('default_picking_id', False):
- picking_type = self.browse(cr, uid, context['default_picking_id'], context=context).type
- if picking_type == 'out':
- context.update({'default_type':'out'})
- view_id = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_out_form')[1]
- elif picking_type == 'in':
- context.update({'default_type':'in'})
- view_id = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_in_form')[1]
- elif picking_type == 'internal':
- context.update({'default_type':'internal'})
- view_id = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_form')[1]
- type = context.get('default_type', False)
- res = super(stock_picking, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
- if type:
- if res.get('toolbar', False):
- # To update the report label according to shipping type
- for report in res['toolbar']['print']:
- if report['report_name'] != 'stock.picking.list':
- continue
- if type == 'in':
- report['string'] = _('Receipt Slip')
- elif type == 'internal':
- report['string'] = _('Picking Slip')
- elif type == 'out':
- report['string'] = _('Delivery Slip')
- report['name'] = report['string']
- for field in res['fields']:
- # To update the states label according to shipping type
- if field == 'state':
- _state = dict(PICK_STATE)
- if type == 'in':
- _state['assigned'] = _('Ready to Receive')
- _state['done'] = _('Received')
- elif type == 'internal':
- _state['assigned'] = _('Ready to Transfer')
- _state['done'] = _('Transferred')
- elif type == 'out':
- _state['assigned'] = _('Ready to Deliver')
- _state['done'] = _('Delivered')
- res['fields']['state']['selection'] = [(x[0], _state[x[0]]) for x in PICK_STATE]
- res['fields']['state']['help'] = self._tooltip_picking_state(_state)
- # To update the fields tooltips according to shipping type
- if field == 'partner_id':
- _tooltip = ''
- if type == 'in':
- _tooltip = _('supplier')
- elif type == 'internal':
- _tooltip = _('warehouse')
- elif type == 'out':
- _tooltip = _('customer')
- res['fields']['partner_id']['help'] = _("Address of %s") %(_tooltip)
- return res
def action_process(self, cr, uid, ids, context=None):
- if context is None: context = {}
- mod_obj = self.pool.get('ir.model.data')
- model_data_ids = mod_obj.search(cr, uid, [('model','=','ir.ui.view'),('name','=','stock_partial_picking_form')], context=context)
- resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
- ctx = context.copy()
- ctx.update({'active_model': 'stock.picking', 'active_ids': ids })
+ if context is None:
+ context = {}
+ context.update({
+ 'active_model': self._name,
+ 'active_ids': ids,
+ 'active_id': len(ids) and ids[0] or False
+ })
return {
'view_type': 'form',
'view_mode': 'form',
'res_model': 'stock.partial.picking',
- 'views': [(resource_id,'form')],
- 'view_id': resource_id,
'type': 'ir.actions.act_window',
'target': 'new',
- 'context': ctx,
+ 'context': context,
'nodestroy': True,
}
for move in picking_obj.move_lines:
move_obj.write(cr, uid, [move.id], {'tracking_id': False,'prodlot_id':False, 'move_history_ids2': [(6, 0, [])], 'move_history_ids': [(6, 0, [])]})
return res
+
+ def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
+ if view_type == 'form' and not view_id:
+ mod_obj = self.pool.get('ir.model.data')
+ if self._name == "stock.picking.in":
+ model,view_id = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_in_form')
+ if self._name == "stock.picking.out":
+ model,view_id = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_out_form')
+ return super(stock_picking,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
def onchange_partner_in(self, cr, uid, context=None, partner_id=None):
return {}
""" Confirms picking.
@return: True
"""
+ pickings = self.browse(cr, uid, ids, context=context)
+ for picking in pickings:
+ if picking.state <> 'confirmed':
+ self.confirm_send_note(cr, uid, [picking.id], context=context)
self.write(cr, uid, ids, {'state': 'confirmed'})
todo = []
- for picking in self.browse(cr, uid, ids, context=context):
+ for picking in pickings:
for r in picking.move_lines:
if r.state == 'draft':
todo.append(r.id)
-
-
todo = self.action_explode(cr, uid, todo, context)
if len(todo):
self.pool.get('stock.move').action_confirm(cr, uid, todo, context=context)
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_confirm', cr)
move_ids = [x.id for x in pick.move_lines if x.state == 'confirmed']
if not move_ids:
- raise osv.except_osv(_('Warning !'),_('Not enough stock, unable to reserve the products.'))
+ raise osv.except_osv(_('Warning!'),_('Not enough stock, unable to reserve the products.'))
self.pool.get('stock.move').action_assign(cr, uid, move_ids)
return True
wf_service = netsvc.LocalService("workflow")
for pick in self.browse(cr, uid, ids):
if not pick.move_lines:
- raise osv.except_osv(_('Error !'),_('You can not process picking without stock moves'))
+ raise osv.except_osv(_('Error!'),_('You cannot process picking without stock moves.'))
wf_service.trg_validate(uid, 'stock.picking', pick.id,
'button_confirm', cr)
return True
ok = True
for pick in self.browse(cr, uid, ids):
mt = pick.move_type
- for move in pick.move_lines:
- # incomming shipments are always set as available
- if pick.type == 'in':
+ # incomming shipments are always set as available if they aren't chained
+ if pick.type == 'in':
+ if all([x.state != 'waiting' for x in pick.move_lines]):
return True
+ for move in pick.move_lines:
if (move.state in ('confirmed', 'draft')) and (mt == 'one'):
return False
if (mt == 'direct') and (move.state == 'assigned') and (move.product_qty):
def _get_partner_to_invoice(self, cr, uid, picking, context=None):
""" Gets the partner that will be invoiced
- Note that this function is inherited in the sale module
+ Note that this function is inherited in the sale and purchase modules
@param picking: object of the picking for which we are selecting the partner to invoice
@return: object of the partner to invoice
"""
return True
for move in pick.move_lines:
if move.state == 'done':
- raise osv.except_osv(_('Error'), _('You cannot cancel picking because stock move is in done state !'))
+ raise osv.except_osv(_('Error!'), _('You cannot cancel the picking as some moves have been done. You should cancel the picking lines.'))
return True
+
def unlink(self, cr, uid, ids, context=None):
move_obj = self.pool.get('stock.move')
if context is None:
context = {}
for pick in self.browse(cr, uid, ids, context=context):
if pick.state in ['done','cancel']:
- raise osv.except_osv(_('Error'), _('You cannot remove the picking which is in %s state !')%(pick.state,))
+ raise osv.except_osv(_('Error!'), _('You cannot remove the picking which is in %s state!')%(pick.state,))
else:
ids2 = [move.id for move in pick.move_lines]
ctx = context.copy()
for move in too_few:
product_qty = move_product_qty[move.id]
if not new_picking:
+ new_picking_name = pick.name
+ self.write(cr, uid, [pick.id],
+ {'name': sequence_obj.get(cr, uid,
+ 'stock.picking.%s'%(pick.type)),
+ })
new_picking = self.copy(cr, uid, pick.id,
{
- 'name': sequence_obj.get(cr, uid, 'stock.picking.%s'%(pick.type)),
+ 'name': new_picking_name,
'move_lines' : [],
'state':'draft',
})
move_obj.copy(cr, uid, move.id, defaults)
move_obj.write(cr, uid, [move.id],
{
- 'product_qty' : move.product_qty - partial_qty[move.id],
+ 'product_qty': move.product_qty - partial_qty[move.id],
'product_uos_qty': move.product_qty - partial_qty[move.id], #TODO: put correct uos_qty
-
+ 'prodlot_id': False,
+ 'tracking_id': False,
})
if new_picking:
delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
res[pick.id] = {'delivered_picking': delivered_pack.id or False}
-
+
return res
def log_picking(self, cr, uid, ids, context=None):
context.update({'view_id': res and res[1] or False})
message += state_list[pick.state]
return True
-
+
# -----------------------------------------
# OpenChatter methods and notifications
# -----------------------------------------
-
- def _get_document_type(self, type):
+
+ def _get_document_type(self, cr, uid, obj, context=None):
type_dict = {
- 'out': 'Delivery order',
- 'in': 'Shipment',
- 'internal': 'Internal picking',
+ 'out': _('Delivery order'),
+ 'in': _('Shipment'),
+ 'internal': _('Internal picking'),
}
- return type_dict.get(type, 'Stock picking')
-
+ return type_dict.get(obj.type, _('Picking'))
+
def create_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
- self.message_append_note(cr, uid, [obj.id], body=_("%s has been <b>created</b>.") % (self._get_document_type(obj.type)), context=context)
-
+ self.message_post(cr, uid, [obj.id], body=_("%s has been <b>created</b>.") % (self._get_document_type(cr, uid, obj, context=context)), context=context)
+
+ def confirm_send_note(self, cr, uid, ids, context=None):
+ for obj in self.browse(cr, uid, ids, context=context):
+ self.message_post(cr, uid, [obj.id], body=_("%s has been <b>confirmed</b>.") % (self._get_document_type(cr, uid, obj, context=context)), context=context)
+
def scrap_send_note(self, cr, uid, ids, quantity, uom, name, context=None):
- return self.message_append_note(cr, uid, ids, body= _("%s %s %s has been <b>moved to</b> scrap.") % (quantity, uom, name), context=context)
-
+ return self.message_post(cr, uid, ids, body= _("%s %s %s has been <b>moved to</b> scrap.") % (quantity, uom, name), context=context)
+
def back_order_send_note(self, cr, uid, ids, back_name, context=None):
- return self.message_append_note(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_name), context=context)
-
+ return self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_name), context=context)
+
def ship_done_send_note(self, cr, uid, ids, context=None):
type_dict = {
- 'out': 'delivered',
- 'in': 'received',
- 'internal': 'moved',
+ 'out': _("Products have been <b>delivered</b>."),
+ 'in': _("Products have been <b>received</b>."),
+ 'internal': _("Products have been <b>moved</b>."),
}
for obj in self.browse(cr, uid, ids, context=context):
- self.message_append_note(cr, uid, [obj.id], body=_("Products have been <b>%s</b>.") % (type_dict.get(obj.type, 'move done')), context=context)
-
+ self.message_post(cr, uid, [obj.id], body=type_dict.get(obj.type, _('Products have been moved.')), context=context)
+
def ship_cancel_send_note(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
- self.message_append_note(cr, uid, [obj.id], body=_("%s has been <b>cancelled</b>.") % (self._get_document_type(obj.type)), context=context)
-
+ self.message_post(cr, uid, [obj.id], body=_("%s has been <b>cancelled</b>.") % (self._get_document_type(cr, uid, obj, context=context)), context=context)
+
stock_picking()
return self.name_get(cr, uid, ids, context)
_name = 'stock.production.lot'
- _description = 'Production lot'
+ _description = 'Serial Number'
def _get_stock(self, cr, uid, ids, field_name, arg, context=None):
""" Gets stock of products for locations
return ids
_columns = {
- 'name': fields.char('Production Lot', size=64, required=True, help="Unique production lot, will be displayed as: PREFIX/SERIAL [INT_REF]"),
+ 'name': fields.char('Serial Number', size=64, required=True, help="Unique Serial Number, will be displayed as: PREFIX/SERIAL [INT_REF]"),
'ref': fields.char('Internal Reference', size=256, help="Internal reference number in case it differs from the manufacturer's serial number"),
'prefix': fields.char('Prefix', size=64, help="Optional prefix to prepend when displaying this serial number: PREFIX/SERIAL [INT_REF]"),
'product_id': fields.many2one('product.product', 'Product', required=True, domain=[('type', '<>', 'service')]),
'date': fields.datetime('Creation Date', required=True),
'stock_available': fields.function(_get_stock, fnct_search=_stock_search, type="float", string="Available", select=True,
- help="Current quantity of products with this Production Lot Number available in company warehouses",
- digits_compute=dp.get_precision('Product UoM')),
+ help="Current quantity of products with this Serial Number available in company warehouses",
+ digits_compute=dp.get_precision('Product Unit of Measure')),
'revisions': fields.one2many('stock.production.lot.revision', 'lot_id', 'Revisions'),
'company_id': fields.many2one('res.company', 'Company', select=True),
- 'move_ids': fields.one2many('stock.move', 'prodlot_id', 'Moves for this production lot', readonly=True),
+ 'move_ids': fields.one2many('stock.move', 'prodlot_id', 'Moves for this serial number', readonly=True),
}
_defaults = {
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
class stock_production_lot_revision(osv.osv):
_name = 'stock.production.lot.revision'
- _description = 'Production lot revisions'
+ _description = 'Serial Number Revision'
_columns = {
'name': fields.char('Revision Name', size=64, required=True),
'date': fields.date('Revision Date'),
'indice': fields.char('Revision Number', size=16),
'author_id': fields.many2one('res.users', 'Author'),
- 'lot_id': fields.many2one('stock.production.lot', 'Production lot', select=True, ondelete='cascade'),
+ 'lot_id': fields.many2one('stock.production.lot', 'Serial Number', select=True, ondelete='cascade'),
'company_id': fields.related('lot_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True),
}
# Fields:
# location_dest_id is only used for predicting futur stocks
#
-MOVE_STATE = [
- ('draft', 'Draft'),
- ('waiting', 'Waiting Another Move'),
- ('confirmed', 'Waiting Availability'),
- ('assigned', 'Available'),
- ('done', 'Done'),
- ('cancel', 'Cancelled')
-]
class stock_move(osv.osv):
def _getSSCC(self, cr, uid, context=None):
cr.execute('select id from stock_tracking where create_uid=%s order by id desc limit 1', (uid,))
res = cr.fetchone()
return (res and res[0]) or False
+
_name = "stock.move"
_description = "Stock Move"
_order = 'date_expected desc, id'
def name_get(self, cr, uid, ids, context=None):
res = []
for line in self.browse(cr, uid, ids, context=context):
- res.append((line.id, (line.product_id.code or '/')+': '+line.location_id.name+' > '+line.location_dest_id.name))
+ name = line.location_id.name+' > '+line.location_dest_id.name
+ # optional prefixes
+ if line.product_id.code:
+ name = line.product_id.code + ': ' + name
+ if line.picking_id.origin:
+ name = line.picking_id.origin + '/ ' + name
+ res.append((line.id, name))
return res
def _check_tracking(self, cr, uid, ids, context=None):
- """ Checks if production lot is assigned to stock move or not.
+ """ Checks if serial number is assigned to stock move or not.
@return: True or False
"""
for move in self.browse(cr, uid, ids, context=context):
return False
return True
- def _tooltip_move_state(self, state=None):
- # Update the tooltip of state field based on shipment type e.g: Delivery, Reception and Internal Transfer
- if state is None:
- state = MOVE_STATE
- _tooltip_state_assigned = state.get('assigned', False)
- _tooltip_state_done = state.get('done', False)
- return _("* Draft: When the stock move is created it is in the \'Draft\' state.\n"\
- "* Waiting Another Move: it is set to \'Waiting Another Move\' state if the scheduler did not find the products.\n"\
- "* Waiting Availability: The state is \'Waiting Availability\' if the move is waiting for another one.\n"\
- "* %s: When products are reserved it is set to \'%s\'.\n"\
- "* %s: When the shipment is done the state is \'%s\'.") % (_tooltip_state_assigned, _tooltip_state_assigned, _tooltip_state_done, _tooltip_state_done)
_columns = {
'name': fields.char('Name', size=250, required=True, select=True),
'priority': fields.selection([('0', 'Not urgent'), ('1', 'Urgent')], 'Priority'),
'date_expected': fields.datetime('Scheduled Date', states={'done': [('readonly', True)]},required=True, select=True, help="Scheduled date for the processing of this move"),
'product_id': fields.many2one('product.product', 'Product', required=True, select=True, domain=[('type','<>','service')],states={'done': [('readonly', True)]}),
- 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product UoM'), required=True,states={'done': [('readonly', True)]}),
+ 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True,states={'done': [('readonly', True)]}),
'product_uom': fields.many2one('product.uom', 'Unit of Measure', required=True,states={'done': [('readonly', True)]}),
- 'product_uos_qty': fields.float('Quantity (UOS)', digits_compute=dp.get_precision('Product UoM'), states={'done': [('readonly', True)]}),
+ 'product_uos_qty': fields.float('Quantity (UOS)', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}),
'product_uos': fields.many2one('product.uom', 'Product UOS', states={'done': [('readonly', True)]}),
'product_packaging': fields.many2one('product.packaging', 'Packaging', help="It specifies attributes of packaging like type, quantity of packaging,etc."),
'location_dest_id': fields.many2one('stock.location', 'Destination Location', required=True,states={'done': [('readonly', True)]}, select=True, help="Location where the system will stock the finished products."),
'partner_id': fields.many2one('res.partner', 'Destination Address ', states={'done': [('readonly', True)]}, help="Optional address where goods are to be delivered, specifically used for allotment"),
- 'prodlot_id': fields.many2one('stock.production.lot', 'Production Lot', states={'done': [('readonly', True)]}, help="Production lot is used to put a serial number on the production", select=True),
+ 'prodlot_id': fields.many2one('stock.production.lot', 'Serial Number', states={'done': [('readonly', True)]}, help="Serial number is used to put a serial number on the production", select=True),
'tracking_id': fields.many2one('stock.tracking', 'Pack', select=True, states={'done': [('readonly', True)]}, help="Logistical shipping unit: pallet, box, pack ..."),
'auto_validate': fields.boolean('Auto Validate'),
'move_history_ids2': fields.many2many('stock.move', 'stock_move_history_ids', 'child_id', 'parent_id', 'Move History (parent moves)'),
'picking_id': fields.many2one('stock.picking', 'Reference', select=True,states={'done': [('readonly', True)]}),
'note': fields.text('Notes'),
- 'state': fields.selection(MOVE_STATE, 'State', readonly=True, select=True,
- help= "* Draft: When the stock move is created it is in the \'Draft\' state.\n"\
- "* Waiting Another Move: it is set to \'Waiting Another Move\' state if the scheduler did not find the products.\n"\
- "* Waiting Availability: The state is \'Waiting Availability\' if the move is waiting for another one.\n"\
- "* Available: When products are reserved it is set to \'Available\'.\n"\
- "* Done: When the shipment is done the state is \'Done\'."),
+ 'state': fields.selection([('draft', 'New'),
+ ('cancel', 'Cancelled'),
+ ('waiting', 'Waiting Another Move'),
+ ('confirmed', 'Waiting Availability'),
+ ('assigned', 'Available'),
+ ('done', 'Done'),
+ ], 'Status', readonly=True, select=True,
+ help= "* New: When the stock move is created and not yet confirmed.\n"\
+ "* Waiting Another Move: This state can be seen when a move is waiting for another one, for example in a chained flow.\n"\
+ "* Waiting Availability: This state is reached when the procurement resolution is not straight forward. It may need the scheduler to run, a component to me manufactured...\n"\
+ "* Available: When products are reserved, it is set to \'Available\'.\n"\
+ "* Done: When the shipment is processed, the state is \'Done\'."),
'price_unit': fields.float('Unit Price', digits_compute= dp.get_precision('Account'), help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"),
'price_currency_id': fields.many2one('res.currency', 'Currency for average price', help="Technical field used to record the currency chosen by the user during a picking confirmation (when average price costing method is used)"),
'company_id': fields.many2one('res.company', 'Company', required=True, select=True),
'backorder_id': fields.related('picking_id','backorder_id',type='many2one', relation="stock.picking", string="Back Order", select=True),
- 'origin': fields.related('picking_id','origin',type='char', size=64, relation="stock.picking", string="Origin", store=True),
+ 'origin': fields.related('picking_id','origin',type='char', size=64, relation="stock.picking", string="Source", store=True),
# used for colors in tree views:
'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True),
+ 'type': fields.related('picking_id', 'type', type='selection', selection=[('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal')], string='Shipping Type'),
}
+
def _check_location(self, cr, uid, ids, context=None):
for record in self.browse(cr, uid, ids, context=context):
- if (record.state=='done') and (record.location_dest_id.usage == 'view' or record.location_id.usage == 'view'):
- return False
+ if (record.state=='done') and (record.location_id.usage == 'view'):
+ raise osv.except_osv(_('Error'), _('You cannot move product %s from a location of type view %s.')% (record.product_id.name, record.location_id.name))
+ if (record.state=='done') and (record.location_dest_id.usage == 'view' ):
+ raise osv.except_osv(_('Error'), _('You cannot move product %s to a location of type view %s.')% (record.product_id.name, record.location_dest_id.name))
return True
_constraints = [
(_check_tracking,
- 'You must assign a production lot for this product',
+ 'You must assign a serial number for this product.',
['prodlot_id']),
- (_check_location, 'You can not move products from or to a location of the type view.',
+ (_check_location, 'You cannot move products from or to a location of the type view.',
['location_id','location_dest_id']),
(_check_product_lot,
- 'You try to assign a lot which is not from the same product',
+ 'You try to assign a lot which is not from the same product.',
['prodlot_id'])]
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- if context is None:
- context = {}
- type = context.get('default_type', False)
- res = super(stock_move, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
- if type:
- doc = etree.XML(res['arch'])
- if type == 'out':
- #To Update button label in case of shipping type is out
- if view_type == 'tree':
- for node in doc.xpath("//button[@string='Receive']"):
- node.set('string', _('Deliver'))
- for node in doc.xpath("//group/button[@string='Process Now']"):
- node.set('string', _('Deliver'))
- for field in res['fields']:
- # To update the states label according to shipping type
- if field == 'state':
- _state = dict(MOVE_STATE)
- if type == 'in':
- _state['assigned'] = _('Ready to Receive')
- _state['done'] = _('Received')
- elif type == 'internal':
- _state['assigned'] = _('Ready to Transfer')
- _state['done'] = _('Transferred')
- elif type == 'out':
- _state['assigned'] = _('Ready to Deliver')
- _state['done'] = _('Delivered')
- res['fields']['state']['selection'] = [(x[0], _state[x[0]]) for x in MOVE_STATE]
- res['fields']['state']['help'] = self._tooltip_move_state(_state)
- res['arch'] = etree.tostring(doc)
- return res
-
def _default_location_destination(self, cr, uid, context=None):
""" Gets default address of partner for destination location
@return: Address id or False
location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id)
return location_id
+ def _default_destination_address(self, cr, uid, context=None):
+ user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+ return user.company_id.partner_id.id
+
+ def _default_move_type(self, cr, uid, context=None):
+ """ Gets default type of move
+ @return: type
+ """
+ if context is None:
+ context = {}
+ picking_type = context.get('picking_type')
+ type = 'internal'
+ if picking_type == 'in':
+ type = 'in'
+ elif picking_type == 'out':
+ type = 'out'
+ return type
+
_defaults = {
'location_id': _default_location_source,
'location_dest_id': _default_location_destination,
+ 'partner_id': _default_destination_address,
+ 'type': _default_move_type,
'state': 'draft',
'priority': '1',
'product_qty': 1.0,
for move in self.browse(cr, uid, ids, context=context):
if move.state == 'done':
if frozen_fields.intersection(vals):
- raise osv.except_osv(_('Operation forbidden'),
- _('Quantities, UoMs, Products and Locations cannot be modified on stock moves that have already been processed (except by the Administrator)'))
+ raise osv.except_osv(_('Operation forbidden !'),
+ _('Quantities, Unit of Measures, Products and Locations cannot be modified on stock moves that have already been processed (except by the Administrator).'))
return super(stock_move, self).write(cr, uid, ids, vals, context=context)
def copy(self, cr, uid, id, default=None, context=None):
warning = {}
if (location.usage == 'internal') and (product_qty > (amount_actual or 0.0)):
warning = {
- 'title': _('Insufficient Stock in Lot !'),
- 'message': _('You are moving %.2f %s products but only %.2f %s available in this lot.') % (product_qty, uom.name, amount_actual, uom.name)
+ 'title': _('Insufficient Stock for Serial Number !'),
+ 'message': _('You are moving %.2f %s but only %.2f %s available for this serial number.') % (product_qty, uom.name, amount_actual, uom.name)
}
return {'warning': warning}
'product_uom': product.uom_id.id,
'product_uos': uos_id,
'product_qty': 1.00,
- 'product_uos_qty' : self.pool.get('stock.move').onchange_quantity(cr, uid, ids, prod_id, 1.00, product.uom_id.id, uos_id)['value']['product_uos_qty']
+ 'product_uos_qty' : self.pool.get('stock.move').onchange_quantity(cr, uid, ids, prod_id, 1.00, product.uom_id.id, uos_id)['value']['product_uos_qty'],
+ 'prodlot_id' : False,
}
if not ids:
result['name'] = product.partner_ref
result['location_dest_id'] = loc_dest_id
return {'value': result}
+ def onchange_move_type(self, cr, uid, ids, type, context=None):
+ """ On change of move type gives sorce and destination location.
+ @param type: Move Type
+ @return: Dictionary of values
+ """
+ mod_obj = self.pool.get('ir.model.data')
+ location_source_id = False
+ location_dest_id = False
+ if type == 'in':
+ location_source_id = 'stock_location_suppliers'
+ location_dest_id = 'stock_location_stock'
+ elif type == 'out':
+ location_source_id = 'stock_location_stock'
+ location_dest_id = 'stock_location_customers'
+ if location_source_id:
+ try:
+ location_model, location_source_id = mod_obj.get_object_reference(cr, uid, 'stock', location_source_id)
+ except ValueError, e:
+ location_source_id = False
+ if location_dest_id:
+ try:
+ location_model, location_dest_id = mod_obj.get_object_reference(cr, uid, 'stock', location_dest_id)
+ except ValueError, e:
+ location_dest_id = False
+ return {'value':{'location_id': location_source_id, 'location_dest_id': location_dest_id}}
+
def onchange_date(self, cr, uid, ids, date, date_expected, context=None):
""" On change of Scheduled Date gives a Move date.
@param date_expected: Scheduled Date
done.append(move.id)
pickings[move.picking_id.id] = 1
r = res.pop(0)
- cr.execute('update stock_move set location_id=%s, product_qty=%s where id=%s', (r[1], r[0], move.id))
+ product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, ids, move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty']
+ cr.execute('update stock_move set location_id=%s, product_qty=%s, product_uos_qty=%s where id=%s', (r[1], r[0],product_uos_qty, move.id))
while res:
r = res.pop(0)
- move_id = self.copy(cr, uid, move.id, {'product_qty': r[0], 'location_id': r[1]})
+ move_id = self.copy(cr, uid, move.id, {'product_uos_qty': product_uos_qty, 'product_qty': r[0], 'location_id': r[1]})
done.append(move_id)
if done:
count += len(done)
return True
if context is None:
context = {}
- pickings = {}
+ pickings = set()
for move in self.browse(cr, uid, ids, context=context):
if move.state in ('confirmed', 'waiting', 'assigned', 'draft'):
if move.picking_id:
- pickings[move.picking_id.id] = True
+ pickings.add(move.picking_id.id)
if move.move_dest_id and move.move_dest_id.state == 'waiting':
self.write(cr, uid, [move.move_dest_id.id], {'state': 'assigned'})
if context.get('call_unlink',False) and move.move_dest_id.picking_id:
wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr)
self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False})
if not context.get('call_unlink',False):
- for pick in self.pool.get('stock.picking').browse(cr, uid, pickings.keys()):
+ for pick in self.pool.get('stock.picking').browse(cr, uid, list(pickings), context=context):
if all(move.state == 'cancel' for move in pick.move_lines):
self.pool.get('stock.picking').write(cr, uid, [pick.id], {'state': 'cancel'})
journal_id = accounts['stock_journal']
if acc_dest == acc_valuation:
- raise osv.except_osv(_('Error!'), _('Can not create Journal Entry, Output Account defined on this product and Valuation account on category of this product are same.'))
+ raise osv.except_osv(_('Error!'), _('Cannot create Journal Entry, Output Account of this product and Valuation account on category of this product are same.'))
if acc_src == acc_valuation:
- raise osv.except_osv(_('Error!'), _('Can not create Journal Entry, Input Account defined on this product and Valuation account on category of this product are same.'))
+ raise osv.except_osv(_('Error!'), _('Cannot create Journal Entry, Input Account of this product and Valuation account on category of this product are same.'))
if not acc_src:
- raise osv.except_osv(_('Error!'), _('There is no stock input account defined for this product or its category: "%s" (id: %d)') % \
+ raise osv.except_osv(_('Error!'), _('Please define stock input account for this product or its category: "%s" (id: %d)') % \
(move.product_id.name, move.product_id.id,))
if not acc_dest:
- raise osv.except_osv(_('Error!'), _('There is no stock output account defined for this product or its category: "%s" (id: %d)') % \
+ raise osv.except_osv(_('Error!'), _('Please define stock output account for this product or its category: "%s" (id: %d)') % \
(move.product_id.name, move.product_id.id,))
if not journal_id:
- raise osv.except_osv(_('Error!'), _('There is no journal defined on the product category: "%s" (id: %d)') % \
+ raise osv.except_osv(_('Error!'), _('Please define journal on the product category: "%s" (id: %d)') % \
(move.product_id.categ_id.name, move.product_id.categ_id.id,))
if not acc_valuation:
- raise osv.except_osv(_('Error!'), _('There is no inventory Valuation account defined on the product category: "%s" (id: %d)') % \
+ raise osv.except_osv(_('Error!'), _('Please define inventory valuation account on the product category: "%s" (id: %d)') % \
(move.product_id.categ_id.name, move.product_id.categ_id.id,))
return journal_id, acc_src, acc_dest, acc_valuation
or move.location_id.company_id != move.location_dest_id.company_id):
journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation(cr, uid, move, src_company_ctx)
reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, src_company_ctx)
- account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_dest, reference_amount, reference_currency_id, context))]
+ #returning goods to supplier
+ if move.location_dest_id.usage == 'supplier':
+ account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_src, reference_amount, reference_currency_id, context))]
+ else:
+ account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_dest, reference_amount, reference_currency_id, context))]
# Incoming moves (or cross-company input part)
if move.location_dest_id.company_id \
or move.location_id.company_id != move.location_dest_id.company_id):
journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation(cr, uid, move, dest_company_ctx)
reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, src_company_ctx)
- account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_src, acc_valuation, reference_amount, reference_currency_id, context))]
+ #goods return from customer
+ if move.location_id.usage == 'customer':
+ account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_dest, acc_valuation, reference_amount, reference_currency_id, context))]
+ else:
+ account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_src, acc_valuation, reference_amount, reference_currency_id, context))]
move_obj = self.pool.get('account.move')
for j_id, move_lines in account_moves:
ctx = context.copy()
for move in self.browse(cr, uid, ids, context=context):
if move.state != 'draft' and not ctx.get('call_unlink',False):
- raise osv.except_osv(_('UserError'),
+ raise osv.except_osv(_('User Error!'),
_('You can only delete draft moves.'))
return super(stock_move, self).unlink(
cr, uid, ids, context=ctx)
"""
#quantity should in MOVE UOM
if quantity <= 0:
- raise osv.except_osv(_('Warning!'), _('Please provide a positive quantity to scrap!'))
+ raise osv.except_osv(_('Warning!'), _('Please provide a positive quantity to scrap.'))
res = []
for move in self.browse(cr, uid, ids, context=context):
move_qty = move.product_qty
if context is None:
context = {}
if quantity <= 0:
- raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
+ raise osv.except_osv(_('Warning!'), _('Please provide proper quantity.'))
res = []
if context is None:
context = {}
if quantity <= 0:
- raise osv.except_osv(_('Warning!'), _('Please provide Proper Quantity !'))
+ raise osv.except_osv(_('Warning!'), _('Please provide proper quantity.'))
res = []
for move in self.browse(cr, uid, ids, context=context):
move_qty = move.product_qty
if move_qty <= 0:
- raise osv.except_osv(_('Error!'), _('Can not consume a move with negative or zero quantity !'))
+ raise osv.except_osv(_('Error!'), _('Cannot consume a move with negative or zero quantity.'))
quantity_rest = move.product_qty
quantity_rest -= quantity
uos_qty_rest = quantity_rest / move_qty * move.product_uos_qty
'location_id': location_id or move.location_id.id,
}
self.write(cr, uid, [move.id], update_val)
-
- product_obj = self.pool.get('product.product')
- for new_move in self.browse(cr, uid, res, context=context):
- message = _("Product has been consumed with '%s' quantity.") % (new_move.product_qty)
- product_obj.message_append_note(cr, uid, [new_move.product_id.id], body=message, context=context)
self.action_done(cr, uid, res, context=context)
if move.state in ('done', 'cancel'):
continue
partial_data = partial_datas.get('move%s'%(move.id), False)
- assert partial_data, _('Missing partial picking data for move #%s') % (move.id)
+ assert partial_data, _('Missing partial picking data for move #%s.') % (move.id)
product_qty = partial_data.get('product_qty',0.0)
move_product_qty[move.id] = product_qty
product_uom = partial_data.get('product_uom',False)
complete.append(self.browse(cr, uid, new_move))
self.write(cr, uid, [move.id],
{
- 'product_qty' : move.product_qty - product_qty,
- 'product_uos_qty':move.product_qty - product_qty,
+ 'product_qty': move.product_qty - product_qty,
+ 'product_uos_qty': move.product_qty - product_qty,
+ 'prodlot_id': False,
+ 'tracking_id': False,
})
'date_done': fields.datetime('Date done'),
'inventory_line_id': fields.one2many('stock.inventory.line', 'inventory_id', 'Inventories', states={'done': [('readonly', True)]}),
'move_ids': fields.many2many('stock.move', 'stock_inventory_move_rel', 'inventory_id', 'move_id', 'Created Moves'),
- 'state': fields.selection( (('draft', 'Draft'), ('done', 'Done'), ('confirm','Confirmed'),('cancel','Cancelled')), 'State', readonly=True, select=True),
+ 'state': fields.selection( (('draft', 'Draft'), ('cancel','Cancelled'), ('confirm','Confirmed'), ('done', 'Done')), 'Status', readonly=True, select=True),
'company_id': fields.many2one('res.company', 'Company', required=True, select=True, readonly=True, states={'draft':[('readonly',False)]}),
}
account_move_data_l = account_move_obj.read(cr, uid, account_move_ids, ['state'], context=context)
for account_move in account_move_data_l:
if account_move['state'] == 'posted':
- raise osv.except_osv(_('UserError'),
+ raise osv.except_osv(_('User Error!'),
_('In order to cancel this inventory, you must first unpost related journal entries.'))
account_move_obj.unlink(cr, uid, [account_move['id']], context=context)
self.write(cr, uid, [inv.id], {'state': 'cancel'}, context=context)
'inventory_id': fields.many2one('stock.inventory', 'Inventory', ondelete='cascade', select=True),
'location_id': fields.many2one('stock.location', 'Location', required=True),
'product_id': fields.many2one('product.product', 'Product', required=True, select=True),
- 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True),
- 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product UoM')),
+ 'product_uom': fields.many2one('product.uom', 'Product Unit of Measure', required=True),
+ 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure')),
'company_id': fields.related('inventory_id','company_id',type='many2one',relation='res.company',string='Company',store=True, select=True, readonly=True),
- 'prod_lot_id': fields.many2one('stock.production.lot', 'Production Lot', domain="[('product_id','=',product_id)]"),
- 'state': fields.related('inventory_id','state',type='char',string='State',readonly=True),
+ 'prod_lot_id': fields.many2one('stock.production.lot', 'Serial Number', domain="[('product_id','=',product_id)]"),
+ 'state': fields.related('inventory_id','state',type='char',string='Status',readonly=True),
+ }
+
+ def _default_stock_location(self, cr, uid, context=None):
+ stock_location = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_stock')
+ return stock_location.id
+
+ _defaults = {
+ 'location_id': _default_stock_location
}
def on_change_product_id(self, cr, uid, ids, location_id, product, uom=False, to_date=False):
@return: Dictionary of changed values
"""
if not product:
- return {'value': {'product_qty': 0.0, 'product_uom': False}}
+ return {'value': {'product_qty': 0.0, 'product_uom': False, 'prod_lot_id': False}}
obj_product = self.pool.get('product.product').browse(cr, uid, product)
uom = uom or obj_product.uom_id.id
amount = self.pool.get('stock.location')._product_get(cr, uid, location_id, [product], {'uom': uom, 'to_date': to_date, 'compute_child': False})[product]
- result = {'product_qty': amount, 'product_uom': uom}
+ result = {'product_qty': amount, 'product_uom': uom, 'prod_lot_id': False}
return {'value': result}
stock_inventory_line()
'lot_stock_id': fields.many2one('stock.location', 'Location Stock', required=True, domain=[('usage','=','internal')]),
'lot_output_id': fields.many2one('stock.location', 'Location Output', required=True, domain=[('usage','<>','view')]),
}
+
+ def _default_lot_input_stock_id(self, cr, uid, context=None):
+ lot_input_stock = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_stock')
+ return lot_input_stock.id
+
+ def _default_lot_output_id(self, cr, uid, context=None):
+ lot_output = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_output')
+ return lot_output.id
+
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.inventory', context=c),
+ 'lot_input_id': _default_lot_input_stock_id,
+ 'lot_stock_id': _default_lot_input_stock_id,
+ 'lot_output_id': _default_lot_output_id,
}
stock_warehouse()
+#----------------------------------------------------------
+# "Empty" Classes that are used to vary from the original stock.picking (that are dedicated to the internal pickings)
+# in order to offer a different usability with different views, labels, available reports/wizards...
+#----------------------------------------------------------
+class stock_picking_in(osv.osv):
+ _name = "stock.picking.in"
+ _inherit = "stock.picking"
+ _table = "stock_picking"
+ _description = "Incomming Shipments"
+
+ def check_access_rights(self, cr, uid, operation, raise_exception=True):
+ #override in order to redirect the check of acces rights on the stock.picking object
+ return self.pool.get('stock.picking').check_access_rights(cr, uid, operation, raise_exception=raise_exception)
+
+ def check_access_rule(self, cr, uid, ids, operation, context=None):
+ #override in order to redirect the check of acces rules on the stock.picking object
+ return self.pool.get('stock.picking').check_access_rule(cr, uid, ids, operation, context=context)
+
+ def _workflow_trigger(self, cr, uid, ids, trigger, context=None):
+ #override in order to trigger the workflow of stock.picking at the end of create, write and unlink operation
+ #instead of it's own workflow (which is not existing)
+ return self.pool.get('stock.picking')._workflow_trigger(cr, uid, ids, trigger, context=context)
+
+ def _workflow_signal(self, cr, uid, ids, signal, context=None):
+ #override in order to fire the workflow signal on given stock.picking workflow instance
+ #instead of it's own workflow (which is not existing)
+ return self.pool.get('stock.picking')._workflow_signal(cr, uid, ids, signal, context=context)
+
+ _columns = {
+ 'backorder_id': fields.many2one('stock.picking.in', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
+ 'state': fields.selection(
+ [('draft', 'Draft'),
+ ('auto', 'Waiting Another Operation'),
+ ('confirmed', 'Waiting Availability'),
+ ('assigned', 'Ready to Receive'),
+ ('done', 'Received'),
+ ('cancel', 'Cancelled'),],
+ 'State', readonly=True, select=True,
+ help="""* Draft: not confirmed yet and will not be scheduled until confirmed\n
+ * Waiting Another Operation: waiting for another move to proceed before it becomes automatically available (e.g. in Make-To-Order flows)\n
+ * Waiting Availability: still waiting for the availability of products\n
+ * Ready to Receive: products reserved, simply waiting for confirmation.\n
+ * Received: has been processed, can't be modified or cancelled anymore\n
+ * Cancelled: has been cancelled, can't be confirmed anymore"""),
+ }
+ _defaults = {
+ 'type': 'in',
+ }
+
+class stock_picking_out(osv.osv):
+ _name = "stock.picking.out"
+ _inherit = "stock.picking"
+ _table = "stock_picking"
+ _description = "Delivery Orders"
+
+ def check_access_rights(self, cr, uid, operation, raise_exception=True):
+ #override in order to redirect the check of acces rights on the stock.picking object
+ return self.pool.get('stock.picking').check_access_rights(cr, uid, operation, raise_exception=raise_exception)
+
+ def check_access_rule(self, cr, uid, ids, operation, context=None):
+ #override in order to redirect the check of acces rules on the stock.picking object
+ return self.pool.get('stock.picking').check_access_rule(cr, uid, ids, operation, context=context)
+
+ def _workflow_trigger(self, cr, uid, ids, trigger, context=None):
+ #override in order to trigger the workflow of stock.picking at the end of create, write and unlink operation
+ #instead of it's own workflow (which is not existing)
+ return self.pool.get('stock.picking')._workflow_trigger(cr, uid, ids, trigger, context=context)
+
+ def _workflow_signal(self, cr, uid, ids, signal, context=None):
+ #override in order to fire the workflow signal on given stock.picking workflow instance
+ #instead of it's own workflow (which is not existing)
+ return self.pool.get('stock.picking')._workflow_signal(cr, uid, ids, signal, context=context)
+
+ _columns = {
+ 'backorder_id': fields.many2one('stock.picking.out', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
+ 'state': fields.selection(
+ [('draft', 'Draft'),
+ ('auto', 'Waiting Another Operation'),
+ ('confirmed', 'Waiting Availability'),
+ ('assigned', 'Ready to Deliver'),
+ ('done', 'Delivered'),
+ ('cancel', 'Cancelled'),],
+ 'State', readonly=True, select=True,
+ help="""* Draft: not confirmed yet and will not be scheduled until confirmed\n
+ * Waiting Another Operation: waiting for another move to proceed before it becomes automatically available (e.g. in Make-To-Order flows)\n
+ * Waiting Availability: still waiting for the availability of products\n
+ * Ready to Deliver: products reserved, simply waiting for confirmation.\n
+ * Delivered: has been processed, can't be modified or cancelled anymore\n
+ * Cancelled: has been cancelled, can't be confirmed anymore"""),
+ }
+ _defaults = {
+ 'type': 'out',
+ }
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: