return self._default_removal_strategy(cr, uid, context=context)
+ def get_warehouse(self, cr, uid, location, context=None):
+ """
+ Returns warehouse id of warehouse that contains location
+ :param location: browse record (stock.location)
+ """
+ wh_obj = self.pool.get("stock.warehouse")
+ whs = wh_obj.search(cr, uid, [('view_location_id.parent_left', '<=', location.parent_left),
+ ('view_location_id.parent_right', '>=', location.parent_left)], context=context)
+ return whs and whs[0] or False
+
#----------------------------------------------------------
# Routes
#----------------------------------------------------------
self.pool.get('stock.move').write(cr, uid, [move.id], {'partially_available': True}, context=context)
def quants_move(self, cr, uid, quants, move, location_to, location_from=False, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, context=None):
- """Moves all given stock.quant in the given destination location.
+ """Moves all given stock.quant in the given destination location. Unreserve from current move.
:param quants: list of tuple(browse record(stock.quant) or None, quantity to move)
:param move: browse record (stock.move)
:param location_to: browse record (stock.location) depicting where the quants have to be moved
def move_quants_write(self, cr, uid, quants, move, location_dest_id, dest_package_id, context=None):
vals = {'location_id': location_dest_id.id,
'history_ids': [(4, move.id)],
- 'package_id': dest_package_id}
+ 'package_id': dest_package_id,
+ 'reservation_id': False}
self.write(cr, SUPERUSER_ID, [q.id for q in quants], vals, context=context)
def quants_get_prefered_domain(self, cr, uid, location, product, qty, domain=None, prefered_domain_list=[], restrict_lot_id=False, restrict_partner_id=False, context=None):
* Cancelled: has been cancelled, can't be confirmed anymore"""
),
'priority': fields.function(get_min_max_date, multi="min_max_date", fnct_inv=_set_priority, type='selection', selection=procurement.PROCUREMENT_PRIORITIES, string='Priority',
- store={'stock.move': (_get_pickings, ['priority'], 20)}, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, select=1, help="Priority for this picking. Setting manually a value here would set it as priority for all the moves",
+ store={'stock.move': (_get_pickings, ['priority', 'picking_id'], 20)}, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, select=1, help="Priority for this picking. Setting manually a value here would set it as priority for all the moves",
track_visibility='onchange', required=True),
'min_date': fields.function(get_min_max_date, multi="min_max_date", fnct_inv=_set_min_date,
- store={'stock.move': (_get_pickings, ['date_expected'], 20)}, type='datetime', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, string='Scheduled Date', select=1, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.", track_visibility='onchange'),
+ store={'stock.move': (_get_pickings, ['date_expected', 'picking_id'], 20)}, type='datetime', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, string='Scheduled Date', select=1, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.", track_visibility='onchange'),
'max_date': fields.function(get_min_max_date, multi="min_max_date",
- store={'stock.move': (_get_pickings, ['date_expected'], 20)}, type='datetime', string='Max. Expected Date', select=2, help="Scheduled time for the last part of the shipment to be processed"),
- 'date': fields.datetime('Commitment Date', help="Date promised for the completion of the transfer order, usually set the time of the order and revised later on.", select=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, track_visibility='onchange'),
+ store={'stock.move': (_get_pickings, ['date_expected', 'picking_id'], 20)}, type='datetime', string='Max. Expected Date', select=2, help="Scheduled time for the last part of the shipment to be processed"),
+ 'date': fields.datetime('Creation Date', help="Creation Date, usually the time of the order", select=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, track_visibility='onchange'),
'date_done': fields.datetime('Date of Transfer', help="Date of Completion", states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=False),
'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, copy=True),
'quant_reserved_exist': fields.function(_get_quant_reserved_exist, type='boolean', string='Quant already reserved ?', help='technical field used to know if there is already at least one quant reserved on moves of a given picking'),
'pack_operation_ids': [],
'backorder_id': picking.id,
})
- self.message_post(cr, uid, picking.id, body=_("Back order <em>%s</em> <b>created</b>.") % (picking.name), context=context)
+ backorder = self.browse(cr, uid, backorder_id, context=context)
+ self.message_post(cr, uid, picking.id, body=_("Back order <em>%s</em> <b>created</b>.") % (backorder.name), context=context)
move_obj = self.pool.get("stock.move")
move_obj.write(cr, uid, backorder_move_ids, {'picking_id': backorder_id}, context=context)
#check if the quant is matching the operation details
if ops.package_id:
- flag = quant.package_id and bool(package_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id]), ('id', '=', quant.package_id.id)], context=context)) or False
+ flag = quant.package_id and bool(package_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id])], context=context)) or False
else:
flag = not quant.package_id.id
flag = flag and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id)
if picking.pack_operation_ids:
self.recompute_remaining_qty(cr, uid, picking, context=context)
+ def _prepare_values_extra_move(self, cr, uid, op, product, remaining_qty, context=None):
+ """
+ Creates an extra move when there is no corresponding original move to be copied
+ """
+ picking = op.picking_id
+ res = {
+ 'picking_id': picking.id,
+ 'location_id': picking.location_id.id,
+ 'location_dest_id': picking.location_dest_id.id,
+ 'product_id': product.id,
+ 'product_uom': product.uom_id.id,
+ 'product_uom_qty': remaining_qty,
+ 'name': _('Extra Move: ') + product.name,
+ 'state': 'draft',
+ }
+ return res
+
def _create_extra_moves(self, cr, uid, picking, context=None):
'''This function creates move lines on a picking, at the time of do_transfer, based on
unexpected product transfers (or exceeding quantities) found in the pack operations.
for product_id, remaining_qty in operation_obj._get_remaining_prod_quantities(cr, uid, op, context=context).items():
if remaining_qty > 0:
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
- vals = {
- 'picking_id': picking.id,
- 'location_id': picking.location_id.id,
- 'location_dest_id': picking.location_dest_id.id,
- 'product_id': product_id,
- 'product_uom': product.uom_id.id,
- 'product_uom_qty': remaining_qty,
- 'name': _('Extra Move: ') + product.name,
- 'state': 'draft',
- }
+ vals = self._prepare_values_extra_move(cr, uid, op, product, remaining_qty, context=context)
moves.append(move_obj.create(cr, uid, vals, context=context))
if moves:
move_obj.action_confirm(cr, uid, moves, context=context)
return moves
+ def rereserve_pick(self, cr, uid, ids, context=None):
+ """
+ This can be used to provide a button that rereserves taking into account the existing pack operations
+ """
+ for pick in self.browse(cr, uid, ids, context=context):
+ self.rereserve_quants(cr, uid, pick, move_ids = [x.id for x in pick.move_lines], context=context)
+
def rereserve_quants(self, cr, uid, picking, move_ids=[], context=None):
""" Unreserve quants then try to reassign quants."""
stock_move_obj = self.pool.get('stock.move')
stock_move_obj.action_assign(cr, uid, move_ids, context=context)
@api.cr_uid_ids_context
+ def do_enter_transfer_details(self, cr, uid, picking, context=None):
+ if not context:
+ context = {}
+
+ context.update({
+ 'active_model': self._name,
+ 'active_ids': picking,
+ 'active_id': len(picking) and picking[0] or False
+ })
+
+ created_id = self.pool['stock.transfer_details'].create(cr, uid, {'picking_id': len(picking) and picking[0] or False}, context)
+ return self.pool['stock.transfer_details'].wizard_view(cr, uid, created_id, context)
+
+
+ @api.cr_uid_ids_context
def do_transfer(self, cr, uid, picking_ids, context=None):
"""
If no pack operation, we do simple action_done of the picking
todo_move_ids = []
if not all_op_processed:
todo_move_ids += self._create_extra_moves(cr, uid, picking, context=context)
-
+
picking.refresh()
#split move lines eventually
-
+
toassign_move_ids = []
for move in picking.move_lines:
remaining_qty = move.remaining_qty
todo_move_ids.append(move.id)
#Assign move as it was assigned before
toassign_move_ids.append(new_move)
- if (need_rereserve or not all_op_processed) and not picking.location_id.usage in ("supplier", "production", "inventory"):
- self.rereserve_quants(cr, uid, picking, move_ids=todo_move_ids, context=context)
+ if need_rereserve or not all_op_processed:
+ if not picking.location_id.usage in ("supplier", "production", "inventory"):
+ self.rereserve_quants(cr, uid, picking, move_ids=todo_move_ids, context=context)
self.do_recompute_remaining_quantities(cr, uid, [picking.id], context=context)
if todo_move_ids and not context.get('do_only_split'):
self.pool.get('stock.move').action_done(cr, uid, todo_move_ids, context=context)
stock_operation_obj.write(cr, uid, operation.id, {'product_qty': operation.product_qty - operation.qty_done,'qty_done': 0, 'lot_id': False}, context=context)
op = stock_operation_obj.browse(cr, uid, new_operation, context=context)
pack_operation_ids.append(op.id)
- for record in op.linked_move_operation_ids:
- stock_move_obj.check_tracking(cr, uid, record.move_id, op.package_id.id or op.lot_id.id, context=context)
+ if op.product_id and op.location_id and op.location_dest_id:
+ stock_move_obj.check_tracking_product(cr, uid, op.product_id, op.lot_id.id, op.location_id, op.location_dest_id, context=context)
package_id = package_obj.create(cr, uid, {}, context=context)
stock_operation_obj.write(cr, uid, pack_operation_ids, {'result_package_id': package_id}, context=context)
return True
res.append((line.id, name))
return res
- def create(self, cr, uid, vals, context=None):
- if vals.get('product_id') and not vals.get('price_unit'):
- prod_obj = self.pool.get('product.product')
- vals['price_unit'] = prod_obj.browse(cr, uid, vals['product_id'], context=context).standard_price
- return super(stock_move, self).create(cr, uid, vals, context=context)
-
def _quantity_normalize(self, cr, uid, ids, name, args, context=None):
uom_obj = self.pool.get('product.uom')
res = {}
self.write(cr, uid, [move.id], {'state': 'confirmed'}, 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 "/")
+ origin = (move.group_id and (move.group_id.name + ":") or "") + (move.rule_id and move.rule_id.name or move.origin or "/")
group_id = move.group_id and move.group_id.id or False
if move.rule_id:
if move.rule_id.group_propagation_option == 'fixed' and move.rule_id.group_id:
if wh_route_ids:
rules = push_obj.search(cr, uid, domain + [('route_id', 'in', wh_route_ids)], order='route_sequence, sequence', context=context)
if not rules:
- #if no specialized push rule has been found yet, we try to find a general one
- rules = push_obj.search(cr, uid, domain, order='route_sequence, sequence', context=context)
+ #if no specialized push rule has been found yet, we try to find a general one (without route)
+ rules = push_obj.search(cr, uid, domain + [('route_id', '=', False)], order='sequence', context=context)
if rules:
rule = push_obj.browse(cr, uid, rules[0], context=context)
push_obj._apply(cr, uid, rule, move, context=context)
product = self.pool.get('product.product').browse(cr, uid, [prod_id], context=ctx)[0]
uos_id = product.uos_id and product.uos_id.id or False
result = {
+ 'name': product.partner_ref,
'product_uom': product.uom_id.id,
'product_uos': uos_id,
'product_uom_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'],
}
- if not ids:
- result['name'] = product.partner_ref
if loc_id:
result['location_id'] = loc_id
if loc_dest_id:
date_expected = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
return {'value': {'date': date_expected}}
+ def attribute_price(self, cr, uid, move, context=None):
+ """
+ Attribute price to move, important in inter-company moves or receipts with only one partner
+ """
+ if not move.price_unit:
+ price = move.product_id.standard_price
+ self.write(cr, uid, [move.id], {'price_unit': price})
def action_confirm(self, cr, uid, ids, context=None):
""" Confirms stock move or put it in waiting if it's linked to another move.
}
to_assign = {}
for move in self.browse(cr, uid, ids, context=context):
+ self.attribute_price(cr, uid, move, context=context)
state = 'confirmed'
#if the move is preceeded, then it's waiting (if preceeding move is done, then action_assign has been called already and its state is already available)
if move.move_orig_ids:
"""
return self.write(cr, uid, ids, {'state': 'assigned'}, context=context)
- 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.
- """
+ def check_tracking_product(self, cr, uid, product, lot_id, location, location_dest, context=None):
check = False
- if move.product_id.track_all and not move.location_dest_id.usage == 'inventory':
+ if product.track_all and not location_dest.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':
+ elif product.track_incoming and location.usage in ('supplier', 'transit', 'inventory') and location_dest.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':
+ elif product.track_outgoing and location_dest.usage in ('customer', 'transit') and location.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))
+ raise osv.except_osv(_('Warning!'), _('You must assign a serial number for the product %s') % (product.name))
+
+
+ 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.
+ """
+ self.check_tracking_product(cr, uid, move.product_id, lot_id, move.location_id, move.location_dest_id, context=context)
+
def action_assign(self, cr, uid, ids, context=None):
""" Checks the product type and accordingly writes the state.
quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id, move.product_id, qty, domain=domain, prefered_domain_list=[], 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, record, context=context)
for move in todo_moves:
+ if move.linked_move_operation_ids:
+ continue
move.refresh()
#then if the move isn't totally assigned, try to find quants without any specific domain
if move.state != 'assigned':
self.write(cr, uid, [move.id], vals, context=context)
def action_done(self, cr, uid, ids, context=None):
- """ Process completly the moves given as ids and if all moves are done, it will finish the picking.
+ """ Process completely the moves given as ids and if all moves are done, it will finish the picking.
"""
context = context or {}
picking_obj = self.pool.get("stock.picking")
main_domain = [('qty', '>', 0)]
for record in ops.linked_move_operation_ids:
move = record.move_id
- self.check_tracking(cr, uid, move, ops.package_id.id or ops.lot_id.id, context=context)
+ self.check_tracking(cr, uid, move, not ops.product_id and ops.package_id.id or ops.lot_id.id, context=context)
prefered_domain = [('reservation_id', '=', move.id)]
fallback_domain = [('reservation_id', '=', False)]
fallback_domain2 = ['&', ('reservation_id', '!=', move.id), ('reservation_id', '!=', False)]
self.pool.get('stock.quant.package').write(cr, SUPERUSER_ID, [ops.package_id.id], {'parent_id': ops.result_package_id.id}, context=context)
move_qty[move.id] -= record.qty
#Check for remaining qtys and unreserve/check move_dest_id in
+ move_dest_ids = set()
for move in self.browse(cr, uid, ids, context=context):
if move_qty[move.id] > 0: # (=In case no pack operations in picking)
main_domain = [('qty', '>', 0)]
qty = move_qty[move.id]
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain, prefered_domain_list=prefered_domain_list, 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, move.location_dest_id, 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)
- #Check moves that were pushed
- if move.move_dest_id.state in ('waiting', 'confirmed'):
- # FIXME is opw 607970 still present with new WMS?
- # (see commits 1ef2c181033bd200906fb1e5ce35e234bf566ac6
- # and 41c5ceb8ebb95c1b4e98d8dd1f12b8e547a24b1d)
- other_upstream_move_ids = self.search(cr, uid, [('id', '!=', move.id), ('state', 'not in', ['done', 'cancel']),
- ('move_dest_id', '=', move.move_dest_id.id)], context=context)
- #If no other moves for the move that got pushed:
- if not other_upstream_move_ids and move.move_dest_id.state in ('waiting', 'confirmed'):
- self.action_assign(cr, uid, [move.move_dest_id.id], context=context)
+ # If the move has a destination, add it to the list to reserve
+ if move.move_dest_id and move.move_dest_id.state in ('waiting', 'confirmed'):
+ move_dest_ids.add(move.move_dest_id.id)
+
if move.procurement_id:
procurement_ids.append(move.procurement_id.id)
+ #unreserve the quants and make them available for other operations/moves
+ quant_obj.quants_unreserve(cr, uid, move, context=context)
# Check the packages have been placed in the correct locations
self._check_package_from_moves(cr, uid, ids, context=context)
#set the move as done
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)
+ #assign destination moves
+ if move_dest_ids:
+ self.action_assign(cr, uid, list(move_dest_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):
defaults = {
'product_uom_qty': uom_qty,
'product_uos_qty': uos_qty,
- 'state': move.state,
'procure_method': 'make_to_stock',
'restrict_lot_id': restrict_lot_id,
'restrict_partner_id': restrict_partner_id,
'product_uos_qty': move.product_uos_qty - uos_qty,
}, context=ctx)
- if move.move_dest_id and move.propagate:
+ if move.move_dest_id and move.propagate and move.move_dest_id.state not in ('done', 'cancel'):
new_move_prop = self.split(cr, uid, move.move_dest_id, qty, context=context)
self.write(cr, uid, [new_move], {'move_dest_id': new_move_prop}, context=context)
#returning the first element of list returned by action_confirm is ok because we checked it wouldn't be exploded (and
return self.action_confirm(cr, uid, [new_move], context=context)[0]
+ def get_code_from_locs(self, cr, uid, move, location_id=False, location_dest_id=False, context=None):
+ """
+ Returns the code the picking type should have. This can easily be used
+ to check if a move is internal or not
+ move, location_id and location_dest_id are browse records
+ """
+ code = 'internal'
+ src_loc = location_id or move.location_id
+ dest_loc = location_dest_id or move.location_dest_id
+ if src_loc.usage == 'internal' and dest_loc.usage != 'internal':
+ code = 'outgoing'
+ if src_loc.usage != 'internal' and dest_loc.usage == 'internal':
+ code = 'incoming'
+ return code
+
+
class stock_inventory(osv.osv):
_name = "stock.inventory"
_description = "Inventory"
domain += ' and lot_id = %s'
args += (inventory.lot_id.id,)
if inventory.product_id:
- domain += 'and product_id = %s'
+ domain += ' and product_id = %s'
args += (inventory.product_id.id,)
if inventory.package_id:
domain += ' and package_id = %s'
'product_qty': 1,
}
+ def create(self, cr, uid, values, context=None):
+ if context is None:
+ context = {}
+ product_obj = self.pool.get('product.product')
+ if 'product_id' in values and not 'product_uom_id' in values:
+ values['product_uom_id'] = product_obj.browse(cr, uid, values.get('product_id'), context=context).uom_id.id
+ return super(stock_inventory_line, self).create(cr, uid, values, context=context)
+
def _resolve_inventory_line(self, cr, uid, inventory_line, context=None):
stock_move_obj = self.pool.get('stock.move')
diff = inventory_line.theoretical_qty - inventory_line.product_qty
'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, select=True),
'partner_id': fields.many2one('res.partner', 'Address'),
'view_location_id': fields.many2one('stock.location', 'View Location', required=True, domain=[('usage', '=', 'view')]),
- 'lot_stock_id': fields.many2one('stock.location', 'Location Stock', required=True, domain=[('usage', '=', 'internal')]),
+ 'lot_stock_id': fields.many2one('stock.location', 'Location Stock', domain=[('usage', '=', 'internal')], required=True),
'code': fields.char('Short Name', size=5, required=True, help="Short name used to identify your warehouse"),
'route_ids': fields.many2many('stock.location.route', 'stock_route_warehouse', 'warehouse_id', 'route_id', 'Routes', domain="[('warehouse_selectable', '=', True)]", help='Defaults routes through the warehouse'),
'reception_steps': fields.selection([
if wh.delivery_steps == 'ship_only':
output_loc = wh.lot_stock_id
# Create extra MTO rule (only for 'ship only' because in the other cases MTO rules already exists)
- mto_pull_vals = self._get_mto_pull_rule(cr, uid, wh, [(output_loc, transit_location, wh.out_type_id.id)], context=context)
+ mto_pull_vals = self._get_mto_pull_rule(cr, uid, wh, [(output_loc, transit_location, wh.out_type_id.id)], context=context)[0]
pull_obj.create(cr, uid, mto_pull_vals, context=context)
inter_wh_route_vals = self._get_inter_wh_route(cr, uid, warehouse, wh, context=context)
inter_wh_route_id = route_obj.create(cr, uid, vals=inter_wh_route_vals, context=context)
if default_resupply_wh and default_resupply_wh.id == wh.id:
self.write(cr, uid, [warehouse.id], {'route_ids': [(4, inter_wh_route_id)]}, context=context)
- def _default_stock_id(self, cr, uid, context=None):
- #lot_input_stock = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_stock')
- try:
- warehouse = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'warehouse0')
- return warehouse.lot_stock_id.id
- except:
- return False
-
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.inventory', context=c),
- 'lot_stock_id': _default_stock_id,
'reception_steps': 'one_step',
'delivery_steps': 'ship_only',
}
def _get_mto_pull_rule(self, cr, uid, warehouse, values, context=None):
mto_route_id = self._get_mto_route(cr, uid, context=context)
- from_loc, dest_loc, pick_type_id = values[0]
- return {
+ res = []
+ for value in values:
+ from_loc, dest_loc, pick_type_id = value
+ res += [{
'name': self._format_rulename(cr, uid, warehouse, from_loc, dest_loc, context=context) + _(' MTO'),
'location_src_id': from_loc.id,
'location_id': dest_loc.id,
'procure_method': 'make_to_order',
'active': True,
'warehouse_id': warehouse.id,
- }
+ }]
+ return res
def _get_crossdock_route(self, cr, uid, warehouse, route_name, context=None):
return {
for pull_rule in pull_rules_list:
pull_obj.create(cr, uid, vals=pull_rule, context=context)
#create MTO pull rule and link it to the generic MTO route
- mto_pull_vals = self._get_mto_pull_rule(cr, uid, warehouse, values, context=context)
+ mto_pull_vals = self._get_mto_pull_rule(cr, uid, warehouse, values, context=context)[0]
mto_pull_id = pull_obj.create(cr, uid, mto_pull_vals, context=context)
#create a route for cross dock operations, that can be set on products and product categories
#change MTO rule
dummy, values = routes_dict[new_delivery_step]
- mto_pull_vals = self._get_mto_pull_rule(cr, uid, warehouse, values, context=context)
+ mto_pull_vals = self._get_mto_pull_rule(cr, uid, warehouse, values, context=context)[0]
pull_obj.write(cr, uid, warehouse.mto_pull_id.id, mto_pull_vals, context=context)
return True
location_obj = self.pool.get('stock.location')
#create view location for warehouse
- wh_loc_id = location_obj.create(cr, uid, {
+ loc_vals = {
'name': _(vals.get('code')),
'usage': 'view',
- 'location_id': data_obj.get_object_reference(cr, uid, 'stock', 'stock_location_locations')[1]
- }, context=context)
+ 'location_id': data_obj.get_object_reference(cr, uid, 'stock', 'stock_location_locations')[1],
+ }
+ if vals.get('company_id'):
+ loc_vals['company_id'] = vals.get('company_id')
+ wh_loc_id = location_obj.create(cr, uid, loc_vals, context=context)
vals['view_location_id'] = wh_loc_id
#create all location
def_values = self.default_get(cr, uid, {'reception_steps', 'delivery_steps'})
{'name': _('Packing Zone'), 'active': delivery_steps == 'pick_pack_ship', 'field': 'wh_pack_stock_loc_id'},
]
for values in sub_locations:
- location_id = location_obj.create(cr, uid, {
+ loc_vals = {
'name': values['name'],
'usage': 'internal',
'location_id': wh_loc_id,
'active': values['active'],
- }, context=context_with_inactive)
+ }
+ if vals.get('company_id'):
+ loc_vals['company_id'] = vals.get('company_id')
+ location_id = location_obj.create(cr, uid, loc_vals, context=context_with_inactive)
vals[values['field']] = location_id
#create WH
route_obj = self.pool.get("stock.location.route")
pull_obj = self.pool.get("procurement.rule")
routes = route_obj.search(cr, uid, [('supplier_wh_id','=', warehouse.id)], context=context)
- pulls= pull_obj.search(cr, uid, ['&', ('route_id', 'in', routes), ('location_id.usage', '=', 'transit')], context=context)
+ pulls = pull_obj.search(cr, uid, ['&', ('route_id', 'in', routes), ('location_id.usage', '=', 'transit')], context=context)
if pulls:
pull_obj.write(cr, uid, pulls, {'location_src_id': new_location, 'procure_method': change_to_multiple and "make_to_order" or "make_to_stock"}, context=context)
# Create or clean MTO rules
transfer_locs = list(set([x.location_id for x in pull_recs]))
vals = [(warehouse.lot_stock_id , x, warehouse.out_type_id.id) for x in transfer_locs]
mto_pull_vals = self._get_mto_pull_rule(cr, uid, warehouse, vals, context=context)
- pull_obj.create(cr, uid, mto_pull_vals, context=context)
+ for mto_pull_val in mto_pull_vals:
+ pull_obj.create(cr, uid, mto_pull_val, context=context)
else:
# We need to delete all the MTO pull rules, otherwise they risk to be used in the system
pulls = pull_obj.search(cr, uid, ['&', ('route_id', '=', mto_route_id), ('location_id.usage', '=', 'transit'), ('location_src_id', '=', warehouse.lot_stock_id.id)], context=context)
'limit': 20
}
+
class stock_location_path(osv.osv):
_name = "stock.location.path"
_description = "Pushed Flows"
'active': True,
}
+ def _prepare_push_apply(self, cr, uid, rule, move, context=None):
+ newdate = (datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta.relativedelta(days=rule.delay or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+ return {
+ 'location_id': move.location_dest_id.id,
+ 'location_dest_id': rule.location_dest_id.id,
+ 'date': newdate,
+ 'company_id': rule.company_id and rule.company_id.id or False,
+ 'date_expected': newdate,
+ 'picking_id': False,
+ 'picking_type_id': rule.picking_type_id and rule.picking_type_id.id or False,
+ 'propagate': rule.propagate,
+ 'push_rule_id': rule.id,
+ 'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False,
+ }
+
def _apply(self, cr, uid, rule, move, context=None):
move_obj = self.pool.get('stock.move')
newdate = (datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta.relativedelta(days=rule.delay or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
#call again push_apply to see if a next step is defined
move_obj._push_apply(cr, uid, [move], context=context)
else:
- move_id = move_obj.copy(cr, uid, move.id, {
- 'location_id': move.location_dest_id.id,
- 'location_dest_id': rule.location_dest_id.id,
- 'date': newdate,
- 'company_id': rule.company_id and rule.company_id.id or False,
- 'date_expected': newdate,
- 'picking_id': False,
- 'picking_type_id': rule.picking_type_id and rule.picking_type_id.id or False,
- 'propagate': rule.propagate,
- 'push_rule_id': rule.id,
- 'warehouse_id': rule.warehouse_id and rule.warehouse_id.id or False,
- })
+ vals = self._prepare_push_apply(cr, uid, rule, move, context=context)
+ move_id = move_obj.copy(cr, uid, move.id, vals, context=context)
move_obj.write(cr, uid, [move.id], {
'move_dest_id': move_id,
})
def _get_package_info(self, cr, uid, ids, name, args, context=None):
default_company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
- res = {}.fromkeys(ids, {'location_id': False, 'company_id': default_company_id, 'owner_id': False})
+ res = dict((res_id, {'location_id': False, 'company_id': default_company_id, 'owner_id': False}) for res_id in ids)
for pack in self.browse(cr, uid, ids, context=context):
if pack.quant_ids:
res[pack.id]['location_id'] = pack.quant_ids[0].location_id.id
def action_print(self, cr, uid, ids, context=None):
context = dict(context or {}, active_ids=ids)
- return self.pool.get("report").get_action(cr, uid, ids, 'stock.report_package_barcode', context=context)
+ return self.pool.get("report").get_action(cr, uid, ids, 'stock.report_package_barcode_small', context=context)
def unpack(self, cr, uid, ids, context=None):
'product_uom_id': fields.many2one('product.uom', 'Product Unit of Measure'),
'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
'qty_done': fields.float('Quantity Processed', digits_compute=dp.get_precision('Product Unit of Measure')),
- 'package_id': fields.many2one('stock.quant.package', 'Package'), # 2
+ 'package_id': fields.many2one('stock.quant.package', 'Source Package'), # 2
'lot_id': fields.many2one('stock.production.lot', 'Lot/Serial Number'),
- 'result_package_id': fields.many2one('stock.quant.package', 'Container Package', help="If set, the operations are packed into this package", required=False, ondelete='cascade'),
+ 'result_package_id': fields.many2one('stock.quant.package', 'Destination Package', help="If set, the operations are packed into this package", required=False, ondelete='cascade'),
'date': fields.datetime('Date', required=True),
'owner_id': fields.many2one('res.partner', 'Owner', help="Owner of the quants"),
#'update_cost': fields.boolean('Need cost update'),
'currency': fields.many2one('res.currency', string="Currency", help="Currency in which Unit cost is expressed", ondelete='CASCADE'),
'linked_move_operation_ids': fields.one2many('stock.move.operation.link', 'operation_id', string='Linked Moves', readonly=True, help='Moves impacted by this operation for the computation of the remaining quantities'),
'remaining_qty': fields.function(_get_remaining_qty, type='float', string='Remaining Qty'),
- 'location_id': fields.many2one('stock.location', 'Location From', required=True),
- 'location_dest_id': fields.many2one('stock.location', 'Location To', required=True),
+ 'location_id': fields.many2one('stock.location', 'Source Location', required=True),
+ 'location_dest_id': fields.many2one('stock.location', 'Destination Location', required=True),
'processed': fields.selection([('true','Yes'), ('false','No')],'Has been processed?', required=True),
}
operation in two to process the one with the qty moved
'''
processed_ids = []
+ move_obj = self.pool.get("stock.move")
for pack_op in self.browse(cr, uid, ids, context=None):
+ if pack_op.product_id and pack_op.location_id and pack_op.location_dest_id:
+ move_obj.check_tracking_product(cr, uid, pack_op.product_id, pack_op.lot_id.id, pack_op.location_id, pack_op.location_dest_id, context=context)
op = pack_op.id
if pack_op.qty_done < pack_op.product_qty:
# we split the operation in two
new_lot_id = lots[0]
val.update({'name': name})
- if not obj.lot_id:
- if not new_lot_id:
- new_lot_id = self.pool.get('stock.production.lot').create(cr, uid, val, context=context)
- self.write(cr, uid, id, {'lot_id': new_lot_id}, context=context)
+ if not new_lot_id:
+ new_lot_id = self.pool.get('stock.production.lot').create(cr, uid, val, context=context)
+ self.write(cr, uid, id, {'lot_id': new_lot_id}, context=context)
def _search_and_increment(self, cr, uid, picking_id, domain, filter_visible=False, visible_op_ids=False, increment=True, context=None):
'''Search for an operation with given 'domain' in a picking, if it exists increment the qty (+1) otherwise create it
"a procurement to bring the forecasted quantity to the Quantity specified as Max Quantity."),
'qty_multiple': fields.float('Qty Multiple', required=True,
digits_compute=dp.get_precision('Product Unit of Measure'),
- help="The procurement quantity will be rounded up to this multiple."),
+ help="The procurement quantity will be rounded up to this multiple. If it is 0, the exact quantity will be used. "),
'procurement_ids': fields.one2many('procurement.order', 'orderpoint_id', 'Created Procurements'),
'group_id': fields.many2one('procurement.group', 'Procurement Group', help="Moves created through this orderpoint will be put in this procurement group. If none is given, the moves generated by procurement rules will be grouped into one big picking.", copy=False),
'company_id': fields.many2one('res.company', 'Company', required=True),
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.warehouse.orderpoint', context=context)
}
_sql_constraints = [
- ('qty_multiple_check', 'CHECK( qty_multiple > 0 )', 'Qty Multiple must be greater than zero.'),
+ ('qty_multiple_check', 'CHECK( qty_multiple >= 0 )', 'Qty Multiple must be greater than or equal to zero.'),
]
_constraints = [
(_check_product_uom, 'You have to select a product unit of measure in the same category than the default unit of measure of the product', ['product_id', 'product_uom']),
def _get_tristate_values(self, cr, uid, ids, field_name, arg, context=None):
picking_obj = self.pool.get('stock.picking')
- res = dict.fromkeys(ids, [])
+ res = {}
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)