'warehouse_selectable': fields.boolean('Applicable on Warehouse'),
'supplied_wh_id': fields.many2one('stock.warehouse', 'Supplied Warehouse'),
'supplier_wh_id': fields.many2one('stock.warehouse', 'Supplier Warehouse'),
+ 'company_id': fields.many2one('res.company', 'Company', select=1, help='Let this field empty if this route is shared between all companies'),
}
_defaults = {
'sequence': lambda self, cr, uid, ctx: 0,
'active': True,
'product_selectable': True,
+ 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.location.route', context=c),
}
def _price_update(self, cr, uid, ids, newprice, context=None):
self.write(cr, SUPERUSER_ID, ids, {'cost': newprice}, context=context)
- def write(self, cr, uid, ids, vals, context=None):
- #We want to trigger the move with nothing on reserved_quant_ids for the store of the remaining quantity
- if 'reservation_id' in vals:
- reservation_ids = self.browse(cr, uid, ids, context=context)
- moves_to_warn = set()
- for reser in reservation_ids:
- if reser.reservation_id:
- moves_to_warn.add(reser.reservation_id.id)
- self.pool.get('stock.move').write(cr, uid, list(moves_to_warn), {'reserved_quant_ids': []}, context=context)
- return super(stock_quant, self).write(cr, SUPERUSER_ID, ids, vals, context=context)
-
def quants_unreserve(self, cr, uid, move, context=None):
related_quants = [x.id for x in move.reserved_quant_ids]
return self.write(cr, SUPERUSER_ID, related_quants, {'reservation_id': False, 'link_move_operation_id': False}, context=context)
'''
domain += location and [('location_id', 'child_of', location.id)] or []
domain += [('product_id', '=', product.id)] + domain
+ #don't take into account location that are production, supplier or inventory
+ ignore_location_ids = self.pool.get('stock.location').search(cr, uid, [('usage', 'in', ('production', 'supplier', 'inventory'))], context=context)
+ domain.append(('location_id','not in',ignore_location_ids))
res = []
offset = 0
while quantity > 0:
raise osv.except_osv(_('Error'), _('You cannot move product %s to a location of type view %s.') % (record.product_id.name, record.location_id.name))
return True
- # FP Note: rehab this, with the auto creation algo
- # def _check_tracking(self, cr, uid, ids, context=None):
- # """ 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):
- # if not move.lot_id and \
- # (move.state == 'done' and \
- # ( \
- # (move.product_id.track_production and move.location_id.usage == 'production') or \
- # (move.product_id.track_production and move.location_dest_id.usage == 'production') or \
- # (move.product_id.track_incoming and move.location_id.usage == 'supplier') or \
- # (move.product_id.track_outgoing and move.location_dest_id.usage == 'customer') or \
- # (move.product_id.track_incoming and move.location_id.usage == 'inventory') \
- # )):
- # return False
- # return True
-
_constraints = [
(_check_location, 'You cannot move products to a location of the type view.', ['location_id'])
- #(_check_tracking, 'You must assign a serial number for this product.', ['prodlot_id']),
]
if not default.get('backorder_id'):
default['backorder_id'] = False
default['pack_operation_ids'] = []
+ default['date_done'] = False
return super(stock_picking, self).copy(cr, uid, id, default, context)
def do_print_delivery(self, cr, uid, ids, context=None):
return True
def cancel_assign(self, cr, uid, ids, context=None):
- """ Cancels picking and moves.
+ """ Cancels picking for the moves that are in the assigned state
@return: True
"""
for pick in self.browse(cr, uid, ids, context=context):
- move_ids = [x.id for x in pick.move_lines]
+ move_ids = [x.id for x in pick.move_lines if x not in ['done', 'cancel']]
self.pool.get('stock.move').cancel_assign(cr, uid, move_ids, context=context)
return True
move_obj = self.pool.get("stock.move")
move_obj.write(cr, uid, backorder_move_ids, {'picking_id': backorder_id}, context=context)
- self.pool.get("stock.picking").action_confirm(cr, uid, [picking.id], context=context)
+ self.write(cr, uid, [picking.id], {'date_done': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
self.action_confirm(cr, uid, [backorder_id], context=context)
return backorder_id
return False
def _create_link_for_product(product_id, qty):
qty_to_assign = qty
for move in picking.move_lines:
- if move.product_id.id == product_id:
+ if move.product_id.id == product_id and move.state not in ['done', 'cancel']:
qty_on_link = min(move.remaining_qty, qty_to_assign)
link_obj.create(cr, uid, {'move_id': move.id, 'operation_id': op.id, 'qty': qty_on_link}, context=context)
qty_to_assign -= qty_on_link
todo_move_ids = []
toassign_move_ids = []
for move in picking.move_lines:
- if move.state == 'draft':
+ if move.state in ('done', 'cancel'):
+ #ignore stock moves cancelled or already done
+ continue
+ elif move.state == 'draft':
toassign_move_ids.append(move.id)
if move.remaining_qty == 0:
if move.state in ('draft', 'assigned', 'confirmed'):
todo_move_ids.append(move.id)
#Assign move as it was assigned before
toassign_move_ids.append(new_move)
- else:
+ elif move.state:
#this should never happens
raise
self.rereserve_quants(cr, uid, picking, move_ids=todo_move_ids, context=context)
('name_ref_uniq', 'unique (name, ref)', 'The combination of Serial Number and internal reference must be unique !'),
]
+ def action_traceability(self, cr, uid, ids, context=None):
+ """ It traces the information of lots
+ @param self: The object pointer.
+ @param cr: A database cursor
+ @param uid: ID of the user currently logged in
+ @param ids: List of IDs selected
+ @param context: A standard dictionary
+ @return: A dictionary of values
+ """
+ quant_obj = self.pool.get("stock.quant")
+ move_obj = self.pool.get("stock.move")
+ quants = quant_obj.search(cr, uid, [('lot_id', 'in', ids)], context=context)
+ moves = set()
+ for quant in quant_obj.browse(cr, uid, quants, context=context):
+ moves |= {move.id for move in quant.history_ids}
+ if moves:
+ return {
+ 'domain': "[('id','in',["+','.join(map(str, list(moves)))+"])]",
+ 'name': _('Traceability'),
+ 'view_mode': 'tree,form',
+ 'view_type': 'form',
+ 'context': {'tree_view_ref': 'stock.view_move_tree'},
+ 'res_model': 'stock.move',
+ 'type': 'ir.actions.act_window',
+ }
+ return False
+
+
# ----------------------------------------------------
# Move
res.add(quant.reservation_id.id)
return list(res)
+ def _get_move_ids(self, cr, uid, ids, context=None):
+ res = []
+ for picking in self.browse(cr, uid, ids, context=context):
+ res += [x.id for x in picking.move_lines]
+ return res
+
_columns = {
'name': fields.char('Description', required=True, select=True),
'priority': fields.selection([('0', 'Not urgent'), ('1', 'Urgent')], 'Priority'),
'move_orig_ids': fields.one2many('stock.move', 'move_dest_id', 'Original Move', help="Optional: previous stock move when chaining them", select=True),
'picking_id': fields.many2one('stock.picking', 'Reference', select=True, states={'done': [('readonly', True)]}),
- 'picking_priority': fields.related('picking_id', 'priority', type='selection', selection=[('0', 'Low'), ('1', 'Normal'), ('2', 'High')], string='Picking Priority'),
+ 'picking_priority': fields.related('picking_id', 'priority', type='selection', selection=[('0', 'Low'), ('1', 'Normal'), ('2', 'High')], string='Picking Priority', store={'stock.picking': (_get_move_ids, ['priority'], 10)}),
'note': fields.text('Notes'),
'state': fields.selection([('draft', 'New'),
('cancel', 'Cancelled'),
quant_obj = self.pool.get("stock.quant")
for move in self.browse(cr, uid, move_ids, context=context):
quant_obj.quants_unreserve(cr, uid, move, context=context)
+ putaway_values = []
+ for putaway_rec in move.putaway_ids:
+ putaway_values.append((2, putaway_rec.id))
+ self.write(cr, uid, [move.id], {'state': 'confirmed', 'putaway_ids': putaway_values}, context=context)
def _prepare_procurement_from_move(self, cr, uid, move, context=None):
origin = (move.group_id and (move.group_id.name + ":") or "") + (move.rule_id and move.rule_id.name or "/")
return True
# Create the stock.move.putaway records
- def _putaway_apply(self, cr, uid, ids, context=None):
+ def _putaway_apply(self, cr, uid, move, putaway, context=None):
+ # Should call different methods here in later versions
moveputaway_obj = self.pool.get('stock.move.putaway')
+ quant_obj = self.pool.get('stock.quant')
+ if putaway.method == 'fixed' and putaway.location_spec_id:
+ for row in quant_obj.read_group(cr, uid, [('reservation_id', '=', move.id)], ['qty', 'lot_id'], ['lot_id'], context=context):
+ vals = {
+ 'move_id': move.id,
+ 'location_id': putaway.location_spec_id.id,
+ 'quantity': row['qty'],
+ 'lot_id': row.get('lot_id') and row['lot_id'][0] or False,
+ }
+ moveputaway_obj.create(cr, SUPERUSER_ID, vals, context=context)
+
+ def _putaway_check(self, cr, uid, ids, context=None):
for move in self.browse(cr, uid, ids, context=context):
putaway = self.pool.get('stock.location').get_putaway_strategy(cr, uid, move.location_dest_id, move.product_id, context=context)
if putaway:
- # Should call different methods here in later versions
- # TODO: take care of lots
- if putaway.method == 'fixed' and putaway.location_spec_id:
- moveputaway_obj.create(cr, SUPERUSER_ID, {'move_id': move.id,
- 'location_id': putaway.location_spec_id.id,
- 'quantity': move.product_qty}, context=context)
- return True
+ self._putaway_apply(cr, uid, move, putaway, context=context)
def _create_procurement(self, cr, uid, move, context=None):
""" This will create a procurement order """
'company_id': move.company_id and move.company_id.id or False,
'move_type': move.group_id and move.group_id.move_type or 'one',
'partner_id': move.group_id and move.group_id.partner_id and move.group_id.partner_id.id or False,
- 'date_done': move.date_expected,
'picking_type_id': move.picking_type_id and move.picking_type_id.id or False,
}
pick = pick_obj.create(cr, uid, values, context=context)
""" Changes the state to assigned.
@return: True
"""
- self.action_assign(cr, uid, ids, context=context)
- self.write(cr, uid, ids, {'state': 'assigned'})
- return True
+ return self.write(cr, uid, ids, {'state': 'assigned'})
def cancel_assign(self, cr, uid, ids, context=None):
""" Changes the state to confirmed.
"""
return self.write(cr, uid, ids, {'state': 'confirmed'})
+ def check_tracking(self, cr, uid, move, lot_id, context=None):
+ """ Checks if serial number is assigned to stock move or not and raise an error if it had to.
+ """
+ check = False
+ if move.product_id.track_all and not move.location_dest_id.usage == 'inventory':
+ check = True
+ elif move.product_id.track_incoming and move.location_id.usage in ('supplier', 'transit', 'inventory') and move.location_dest_id.usage == 'internal':
+ check = True
+ elif move.product_id.track_outgoing and move.location_dest_id.usage in ('customer', 'transit') and move.location_id.usage == 'internal':
+ check = True
+ if check and not lot_id:
+ raise osv.except_osv(_('Warning!'), _('You must assign a serial number for the product %s') % (move.product_id.name))
+
def action_assign(self, cr, uid, ids, context=None):
""" Checks the product type and accordingly writes the state.
- @return: No. of moves done
"""
context = context or {}
quant_obj = self.pool.get("stock.quant")
- done = []
+ to_assign_moves = []
for move in self.browse(cr, uid, ids, context=context):
if move.state not in ('confirmed', 'waiting', 'assigned'):
continue
if move.product_id.type == 'consu':
- done.append(move.id)
+ to_assign_moves.append(move.id)
continue
else:
#build the prefered domain based on quants that moved in previous linked done move
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain, prefered_domain=prefered_domain, fallback_domain=fallback_domain, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
quant_obj.quants_reserve(cr, uid, quants, move, context=context)
- self._putaway_apply(cr, uid, ids, context=context)
+ #force assignation of consumable products
+ if to_assign_moves:
+ self.force_assign(cr, uid, to_assign_moves, context=context)
+ #check if a putaway rule is likely to be processed and store result on the move
+ self._putaway_check(cr, uid, ids, context=context)
def action_cancel(self, cr, uid, ids, context=None):
""" Cancels the moves and if all moves are cancelled it cancels the picking.
@return:
"""
context = context or {}
+ picking_obj = self.pool.get("stock.picking")
quant_obj = self.pool.get("stock.quant")
pack_op_obj = self.pool.get("stock.pack.operation")
todo = [move.id for move in self.browse(cr, uid, ids, context=context) if move.state == "draft"]
fallback_domain = [('reservation_id', '=', False)]
#first, process the move per linked operation first because it may imply some specific domains to consider
for record in move.linked_move_operation_ids:
+ self.check_tracking(cr, uid, move, record.operation_id.lot_id.id, context=context)
dom = main_domain + self.pool.get('stock.move.operation.link').get_specific_domain(cr, uid, record, context=context)
- quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, record.qty, domain=dom, prefered_domain=prefered_domain, fallback_domain=fallback_domain, context=context)
+ quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, record.qty, domain=dom, prefered_domain=prefered_domain, fallback_domain=fallback_domain, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
package_id = False
if not record.operation_id.package_id:
#if a package and a result_package is given, we don't enter here because it will be processed by process_packaging() later
qty -= record.qty
#then if the total quantity processed this way isn't enough, process the remaining quantity without any specific domain
if qty > 0:
- quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain, prefered_domain=prefered_domain, fallback_domain=fallback_domain, context=context)
- quant_obj.quants_move(cr, uid, quants, move, context=context)
+ self.check_tracking(cr, uid, move, move.restrict_lot_id.id, context=context)
+ quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain, prefered_domain=prefered_domain, fallback_domain=fallback_domain, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
+ quant_obj.quants_move(cr, uid, quants, move, lot_id=move.restrict_lot_id.id, owner_id=move.restrict_partner_id.id, context=context)
#unreserve the quants and make them available for other operations/moves
quant_obj.quants_unreserve(cr, uid, move, context=context)
procurement_ids.append(move.procurement_id.id)
self.write(cr, uid, ids, {'state': 'done', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
self.pool.get('procurement.order').check(cr, uid, procurement_ids, context=context)
+ #check picking state to set the date_done is needed
+ done_picking = []
+ for picking in picking_obj.browse(cr, uid, list(pickings), context=context):
+ if picking.state == 'done' and not picking.date_done:
+ done_picking.append(picking.id)
+ if done_picking:
+ picking_obj.write(cr, uid, done_picking, {'date_done': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
return True
def unlink(self, cr, uid, ids, context=None):
raise osv.except_osv(_('User Error!'), _('You can only delete draft moves.'))
return super(stock_move, self).unlink(cr, uid, ids, context=context)
- def action_scrap(self, cr, uid, ids, quantity, location_id, context=None):
+ def action_scrap(self, cr, uid, ids, quantity, location_id, restrict_lot_id=False, restrict_partner_id=False, context=None):
""" Move the scrap/damaged product into scrap location
@param cr: the database cursor
@param uid: the user id
'state': move.state,
'scrapped': True,
'location_dest_id': location_id,
- #TODO lot_id is now on quant and not on move, need to do something for this
- #'lot_id': move.lot_id.id,
+ 'restrict_lot_id': restrict_lot_id,
+ 'restrict_partner_id': restrict_partner_id,
}
new_move = self.copy(cr, uid, move.id, default_val)
self.action_done(cr, uid, res, context=context)
return res
- def action_consume(self, cr, uid, ids, quantity, location_id=False, context=None):
+ def action_consume(self, cr, uid, ids, quantity, location_id=False, restrict_lot_id=False, restrict_partner_id=False, context=None):
""" Consumed product with specific quantity from specific source location. This correspond to a split of the move (or write if the quantity to consume is >= than the quantity of the move) followed by an action_done
@param ids: ids of stock move object to be consumed
@param quantity : specify consume quantity (given in move UoM)
ctx = context.copy()
if location_id:
ctx['source_location_id'] = location_id
- res.append(self.split(cr, uid, move, move_qty - quantity_rest, ctx))
+ res.append(self.split(cr, uid, move, move_qty - quantity_rest, restrict_lot_id=restrict_lot_id,
+ restrict_partner_id=restrict_partner_id, context=ctx))
else:
res.append(move.id)
if location_id:
- self.write(cr, uid, [move.id], {'location_id': location_id}, context=context)
+ self.write(cr, uid, [move.id], {'location_id': location_id, 'restrict_lot_id': restrict_lot_id,
+ 'restrict_partner_id': restrict_partner_id}, context=context)
self.action_done(cr, uid, res, context=context)
return res
- def split(self, cr, uid, move, qty, context=None):
+ def split(self, cr, uid, move, qty, restrict_lot_id=False, restrict_partner_id=False, context=None):
""" Splits qty from move move into a new move
:param move: browse record
:param qty: float. quantity to split (given in product UoM)
'state': move.state,
'procure_method': 'make_to_stock',
'move_dest_id': False,
- 'reserved_quant_ids': []
+ 'reserved_quant_ids': [],
+ 'restrict_lot_id': restrict_lot_id,
+ 'restrict_partner_id': restrict_partner_id
}
if context.get('source_location_id'):
defaults['location_id'] = context['source_location_id']
:rtype: list of tuple
"""
#default available choices
- res_filter = [('none', ' All products of a whole location'), ('product', 'One product only')]
+ res_filter = [('none', _('All products of a whole location')), ('product', _('One product only'))]
settings_obj = self.pool.get('stock.config.settings')
config_ids = settings_obj.search(cr, uid, [], limit=1, order='id DESC', context=context)
#If we don't have updated config until now, all fields are by default false and so should be not dipslayed
if stock_settings.group_stock_tracking_owner:
res_filter.append(('owner', _('One owner only')))
res_filter.append(('product_owner', _('One product for a specific owner')))
- if stock_settings.group_stock_production_lot:
- res_filter.append(('lot', _('One Lot/Serial Number')))
if stock_settings.group_stock_tracking_lot:
+ res_filter.append(('lot', _('One Lot/Serial Number')))
+ if stock_settings.group_stock_packaging:
res_filter.append(('pack', _('A Pack')))
return res_filter
return True
def action_cancel_inventory(self, cr, uid, ids, context=None):
- #TODO test
self.action_cancel_draft(cr, uid, ids, context=context)
def prepare_inventory(self, cr, uid, ids, context=None):
_name = "stock.inventory.line"
_description = "Inventory Line"
_rec_name = "inventory_id"
+ _order = "inventory_id, location_name, product_code, product_name, prod_lot_id"
+
+ def _get_product_name_change(self, cr, uid, ids, context=None):
+ return self.pool.get('stock.inventory.line').search(cr, uid, [('product_id', 'in', ids)], context=context)
+
+ def _get_location_change(self, cr, uid, ids, context=None):
+ return self.pool.get('stock.inventory.line').search(cr, uid, [('location_id', 'in', ids)], context=context)
+
_columns = {
'inventory_id': fields.many2one('stock.inventory', 'Inventory', ondelete='cascade', select=True),
'location_id': fields.many2one('stock.location', 'Location', required=True, select=True),
'state': fields.related('inventory_id', 'state', type='char', string='Status', readonly=True),
'th_qty': fields.float('Theoretical Quantity', readonly=True),
'partner_id': fields.many2one('res.partner', 'Owner'),
+ 'product_name': fields.related('product_id', 'name', type='char', string='Product name', store={
+ 'product.product': (_get_product_name_change, ['name', 'default_code'], 20),
+ 'stock.inventory.line': (lambda self, cr, uid, ids, c={}: ids, ['product_id'], 20),}),
+ 'product_code': fields.related('product_id', 'default_code', type='char', string='Product code', store={
+ 'product.product': (_get_product_name_change, ['name', 'default_code'], 20),
+ 'stock.inventory.line': (lambda self, cr, uid, ids, c={}: ids, ['product_id'], 20),}),
+ 'location_name': fields.related('location_id', 'complete_name', type='char', string='Location name', store={
+ 'stock.location': (_get_location_change, ['name', 'location_id', 'active'], 20),
+ 'stock.inventory.line': (lambda self, cr, uid, ids, c={}: ids, ['location_id'], 20),}),
}
_defaults = {
vals[values['field']] = location_id
#create new sequences
- in_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence in'), 'prefix': vals.get('code', '') + '\IN\\', 'padding': 5}, context=context)
- out_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence out'), 'prefix': vals.get('code', '') + '\OUT\\', 'padding': 5}, context=context)
- pack_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence packing'), 'prefix': vals.get('code', '') + '\PACK\\', 'padding': 5}, context=context)
- pick_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence picking'), 'prefix': vals.get('code', '') + '\PICK\\', 'padding': 5}, context=context)
- int_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence internal'), 'prefix': vals.get('code', '') + '\INT\\', 'padding': 5}, context=context)
+ in_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence in'), 'prefix': vals.get('code', '') + '/IN/', 'padding': 5}, context=context)
+ out_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence out'), 'prefix': vals.get('code', '') + '/OUT/', 'padding': 5}, context=context)
+ pack_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence packing'), 'prefix': vals.get('code', '') + '/PACK/', 'padding': 5}, context=context)
+ pick_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence picking'), 'prefix': vals.get('code', '') + '/PICK/', 'padding': 5}, context=context)
+ int_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': vals.get('name', '') + _(' Sequence internal'), 'prefix': vals.get('code', '') + '/INT/', 'padding': 5}, context=context)
#create WH
new_id = super(stock_warehouse, self).create(cr, uid, vals=vals, context=context)
'warehouse_id': new_id,
'code': 'outgoing',
'sequence_id': out_seq_id,
+ 'return_picking_type_id': in_type_id,
'default_location_src_id': output_loc.id,
'default_location_dest_id': customer_loc.id,
'sequence': max_sequence + 4,
'color': color}, context=context)
+ picking_type_obj.write(cr, uid, [in_type_id], {'return_picking_type_id': out_type_id}, context=context)
int_type_id = picking_type_obj.create(cr, uid, vals={
'name': _('Internal Transfers'),
'warehouse_id': new_id,
def _get_rules(self, cr, uid, ids, context=None):
res = []
- for route in self.browse(cr, uid, ids):
+ for route in self.browse(cr, uid, ids, context=context):
res += [x.id for x in route.push_ids]
return res
if quant:
if operation.product_id:
#if a product + a package information is given, we consider that we took a part of an existing package (unpacking)
- quant_obj.write(cr, uid, quant.id, {'package_id': operation.result_package_id.id}, context=context)
+ quant_obj.write(cr, SUPERUSER_ID, quant.id, {'package_id': operation.result_package_id.id}, context=context)
elif operation.package_id and operation.result_package_id:
#move the whole pack into the final package if any
pack_obj.write(cr, uid, [operation.package_id.id], {'parent_id': operation.result_package_id.id}, context=context)
"""
month_begin = date.today().replace(day=1)
section_result = [{
- 'value': 0,
- 'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B'),
- } for i in range(10, -1, -1)]
+ 'value': 0,
+ 'tooltip': (month_begin + relativedelta.relativedelta(months=i)).strftime('%B'),
+ } for i in range(-2, 2, 1)]
group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context)
for group in group_obj:
group_begin_date = datetime.strptime(group['__domain'][0][2], DEFAULT_SERVER_DATE_FORMAT)
month_delta = relativedelta.relativedelta(month_begin, group_begin_date)
- section_result[10 - (month_delta.months + 1)] = {'value': group.get(value_field, 0), 'tooltip': group_begin_date.strftime('%B')}
+ section_result[-month_delta.months + 2] = {'value': group.get(value_field, 0), 'tooltip': group_begin_date.strftime('%B')}
inner_groupby = (group.get('__context', {})).get('group_by',[])
if inner_groupby:
groupby_picking = obj.read_group(cr, uid, group.get('__domain'), read_fields, inner_groupby, context=context)
for groupby in groupby_picking:
- section_result[10 - (month_delta.months + 1)]['value'] = groupby.get(value_field, 0)
+ section_result[-month_delta.months + 2]['value'] = groupby.get(value_field, 0)
return section_result
- def _get_picking_data(self, cr, uid, ids, field_name, arg, context=None):
+ def _get_tristate_values(self, cr, uid, ids, field_name, arg, context=None):
+ picking_obj = self.pool.get('stock.picking')
+ res = dict.fromkeys(ids, [])
+ for picking_type_id in ids:
+ #get last 10 pickings of this type
+ picking_ids = picking_obj.search(cr, uid, [('picking_type_id', '=', picking_type_id), ('state', '=', 'done')], order='date_done desc', limit=10, context=context)
+ tristates = []
+ for picking in picking_obj.browse(cr, uid, picking_ids, context=context):
+ if picking.date_done > picking.date:
+ tristates.insert(0, {'tooltip': picking.name + _(': Late'), 'value': -1})
+ elif picking.backorder_id:
+ tristates.insert(0, {'tooltip': picking.name + _(': Backorder exists'), 'value': 0})
+ else:
+ tristates.insert(0, {'tooltip': picking.name + _(': OK'), 'value': 1})
+ res[picking_type_id] = tristates
+ return res
+
+
+
+ def _get_monthly_pickings(self, cr, uid, ids, field_name, arg, context=None):
obj = self.pool.get('stock.picking')
res = dict.fromkeys(ids, False)
month_begin = date.today().replace(day=1)
- groupby_begin = (month_begin + relativedelta.relativedelta(months=-4)).strftime(DEFAULT_SERVER_DATE_FORMAT)
- groupby_end = (month_begin + relativedelta.relativedelta(months=3)).strftime(DEFAULT_SERVER_DATE_FORMAT)
+ groupby_begin = (month_begin + relativedelta.relativedelta(months=-2)).strftime(DEFAULT_SERVER_DATE_FORMAT)
+ groupby_end = (month_begin + relativedelta.relativedelta(months=2)).strftime(DEFAULT_SERVER_DATE_FORMAT)
for id in ids:
created_domain = [
('picking_type_id', '=', id),
- ('state', 'not in', ['done', 'cancel']),
+ ('state', '=', 'done'),
('date', '>=', groupby_begin),
('date', '<', groupby_end),
]
obj = self.pool.get('stock.picking')
domains = {
'count_picking_draft': [('state', '=', 'draft')],
- 'count_picking_waiting': [('state','in', ('confirmed', 'waiting'))],
+ 'count_picking_waiting': [('state','=', 'confirmed')],
'count_picking_ready': [('state','=','assigned')],
'count_picking': [('state','in',('assigned','waiting','confirmed'))],
'count_picking_late': [('min_date','<', time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)), ('state','in',('assigned','waiting','confirmed'))],
'active': fields.boolean('Active'),
# Statistics for the kanban view
- 'weekly_picking': fields.function(_get_picking_data,
+ 'monthly_picking': fields.function(_get_monthly_pickings,
+ type='string',
+ string='Done Pickings per Month'),
+ 'last_done_picking': fields.function(_get_tristate_values,
type='string',
- string='Scheduled pickings per week'),
+ string='Last 10 Done Pickings'),
'count_picking_draft': fields.function(_get_picking_count,
type='integer', multi='_get_picking_count'),