diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 1916a50832d..6cf858284be 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -212,6 +212,7 @@ class stock_quant(osv.osv): 'package_id': fields.many2one('stock.quant.package', string='Package', help="The package containing this quant"), 'packaging_type_id': fields.related('package_id', 'packaging_id', type='many2one', relation='product.packaging', string='Type of packaging', store=True), 'reservation_id': fields.many2one('stock.move', 'Reserved for Move', help="The move the quant is reserved for"), + 'link_move_operation_id': fields.many2one('stock.move.operation.link', 'Reserved for Link between Move and Pack Operation', help="Technical field decpicting for with tuple (move, operation) this quant is reserved for"), 'lot_id': fields.many2one('stock.production.lot', 'Lot'), 'cost': fields.float('Unit Cost'), 'owner_id': fields.many2one('res.partner', 'Owner', help="This is the owner of the quant"), @@ -250,10 +251,11 @@ class stock_quant(osv.osv): result['domain'] = "[('id','in',[" + ','.join(map(str, move_ids)) + "])]" return result - def quants_reserve(self, cr, uid, quants, move, context=None): + def quants_reserve(self, cr, uid, quants, move, link=False, context=None): '''This function reserves quants for the given move. If the total of quantity reserved is enough, the move's state is also set to 'assigned' :param quants: list of tuple(quant browse record or None, qty to reserve). If None is given as first tuple element, the item will be ignored :param move: browse record + :param link: browse record (stock.move.operation.link) ''' toreserve = [] #split quants if needed @@ -264,24 +266,25 @@ class stock_quant(osv.osv): toreserve.append(quant.id) #reserve quants if toreserve: - self.write(cr, SUPERUSER_ID, toreserve, {'reservation_id': move.id}, context=context) + self.write(cr, SUPERUSER_ID, toreserve, {'reservation_id': move.id, 'link_move_operation_id': link and link.id or False}, context=context) #check if move'state needs to be set as 'assigned' move.refresh() if sum([q.qty for q in move.reserved_quant_ids]) == move.product_qty and move.state == 'confirmed': self.pool.get('stock.move').write(cr, uid, [move.id], {'state': 'assigned'}, context=context) - def quants_move(self, cr, uid, quants, move, lot_id=False, owner_id=False, package_id=False, context=None): + def quants_move(self, cr, uid, quants, move, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, context=None): """Moves all given stock.quant in the destination location of the given move. :param quants: list of tuple(browse record(stock.quant) or None, quantity to move) :param move: browse record (stock.move) :param lot_id: ID of the lot that mus be set on the quants to move :param owner_id: ID of the partner that must own the quants to move - :param package_id: ID of the package that must contains the quants to move + :param src_package_id: ID of the package that contains the quants to move + :param dest_package_id: ID of the package that must be set on the moved quant """ for quant, qty in quants: if not quant: #If quant is None, we will create a quant to move (and potentially a negative counterpart too) - quant = self._quant_create(cr, uid, qty, move, lot_id=lot_id, owner_id=owner_id, package_id=package_id, context=context) + quant = self._quant_create(cr, uid, qty, move, lot_id=lot_id, owner_id=owner_id, src_package_id=src_package_id, dest_package_id=dest_package_id, context=context) self.move_single_quant_tuple(cr, uid, quant, qty, move, context=context) def check_preferred_location(self, cr, uid, move, qty, context=None): @@ -296,7 +299,7 @@ class stock_quant(osv.osv): res = [] for record in move.putaway_ids: res.append((record.location_id, record.quantity)) - return res + return res return [(move.location_dest_id, qty)] def move_single_quant(self, cr, uid, quant, location_to, qty, move, context=None): @@ -309,10 +312,14 @@ class stock_quant(osv.osv): :param move: browse record (stock.move) ''' new_quant = self._quant_split(cr, uid, quant, qty, context=context) - self.write(cr, SUPERUSER_ID, [quant.id], { + vals = { 'location_id': location_to.id, - 'history_ids': [(4, move.id)] - }) + 'history_ids': [(4, move.id)], + } + #if the quant we are moving had been split and was inside a package, it means we unpacked it + if new_quant and new_quant.package_id: + vals['package_id'] = False + self.write(cr, SUPERUSER_ID, [quant.id], vals, context=context) quant.refresh() return new_quant @@ -381,7 +388,7 @@ class stock_quant(osv.osv): raise osv.except_osv(_('Error!'), _('Removal strategy %s not implemented.' % (removal_strategy,))) return result - def _quant_create(self, cr, uid, qty, move, lot_id=False, owner_id=False, package_id=False, force_location=False, context=None): + def _quant_create(self, cr, uid, qty, move, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, force_location=False, context=None): '''Create a quant in the destination location and create a negative quant in the source location if it's an internal location. ''' if context is None: @@ -398,6 +405,7 @@ class stock_quant(osv.osv): 'company_id': move.company_id.id, 'lot_id': lot_id, 'owner_id': owner_id, + 'package_id': dest_package_id, } if move.location_id.usage == 'internal': @@ -408,7 +416,7 @@ class stock_quant(osv.osv): negative_vals['qty'] = -qty negative_vals['cost'] = price_unit negative_vals['negative_dest_location_id'] = move.location_dest_id.id - negative_vals['package_id'] = package_id + negative_vals['package_id'] = src_package_id negative_quant_id = self.create(cr, SUPERUSER_ID, negative_vals, context=context) vals.update({'propagated_from_id': negative_quant_id}) @@ -498,7 +506,7 @@ class stock_quant(osv.osv): 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}, context=context) + return self.write(cr, SUPERUSER_ID, related_quants, {'reservation_id': False, 'link_move_operation_id': False}, context=context) def _quants_get_order(self, cr, uid, location, product, quantity, domain=[], orderby='in_date', context=None): ''' Implementation of removal strategies @@ -767,46 +775,14 @@ class stock_picking(osv.osv): also impact the state of the picking as it is computed based on move's states. @return: True """ - def build_domain(record): - op = record.operation_id - move = record.move_id - domain = [('product_id', '=', move.product_id.id)] - if op.package_id: - domain.append(('id', 'in', package_obj.get_content(cr, uid, [op.package_id.id], context=context))) - elif op.quant_id: - domain.append(('id', '=', op.quant_id.id)) - elif op.lot_id: - domain.append(('lot_id', '=', op.lot_id.id)) - else: - #fallback on the default behavior - return [] - return domain - - package_obj = self.pool.get('stock.quant.package') - quant_obj = self.pool.get('stock.quant') - deferred_move_ids = [] for pick in self.browse(cr, uid, ids, context=context): if pick.state == 'draft': self.action_confirm(cr, uid, [pick.id], context=context) + #skip the moves that don't need to be checked move_ids = [x.id for x in pick.move_lines if x.state not in ('draft', 'cancel', 'done')] if not move_ids: raise osv.except_osv(_('Warning!'), _('Nothing to check the availability for.')) - for move in pick.move_lines: - #skip the move that doesn't need to be checked - if move.state in ('draft', 'cancel', 'done'): - continue - #assign quants based on the pack operations of the picking - for record in move.linked_move_operation_ids: - domain = build_domain(record) - if domain: - quants = quant_obj.quants_get(cr, uid, move.location_id, move.product_id, record.qty, domain=domain) - quant_obj.quants_reserve(cr, uid, quants, move, context=context) - #if the move is still not totally available (not possible to reserve everything based on the pack operations), - #queue this move in the list to recompute based on generic action_assign of the move. - if move.state != 'assigned': - deferred_move_ids.append(move.id) - if deferred_move_ids: - self.pool.get('stock.move').action_assign(cr, uid, deferred_move_ids, context=context) + self.pool.get('stock.move').action_assign(cr, uid, move_ids, context=context) return True def force_assign(self, cr, uid, ids, context=None): @@ -861,6 +837,12 @@ class stock_picking(osv.osv): move_obj.unlink(cr, uid, ids2, context=context) return super(stock_picking, self).unlink(cr, uid, ids, context=context) + def write(self, cr, uid, ids, vals, context=None): + res = super(stock_picking, self).write(cr, uid, ids, vals, context=context) + if 'move_lines' in vals or 'pack_operation_ids' in vals: + self.do_recompute_remaining_quantities(cr, uid, ids, context=context) + return res + def _create_backorder(self, cr, uid, picking, backorder_moves=[], context=None): """ Move all non-done lines into a new backorder picking. If the key 'do_only_split' is given in the context, then move all lines not in context.get('split', []) instead of all non-done lines. @@ -958,13 +940,6 @@ class stock_picking(osv.osv): 'cost': move.product_id.standard_price, }, context=context) - def available_quants_assign(self, cr, uid, picking_ids, context=None): - '''Recompute the availability of quants for the given picking and assign them on the stock moves''' - #first unreserve the quants of related picking, because this function could be used to unreserve - #quants on several pickings in order to group the available ones on a single picking. - self.do_unreserve(cr, uid, picking_ids, context=context) - return self.action_assign(cr, uid, picking_ids, context=context) - def do_unreserve(self, cr, uid, picking_ids, context=None): """ Will remove all quants for picking in picking_ids @@ -994,12 +969,12 @@ class stock_picking(osv.osv): to_unlink_ids = [x.id for x in op.linked_move_operation_ids] if to_unlink_ids: link_obj.unlink(cr, uid, to_unlink_ids, context=context) - if op.package_id: - for product_id, qty in package_obj._get_all_products_quantities(cr, uid, op.package_id.id, context=context).items(): - _create_link_for_product(product_id, qty) - elif op.product_id: + if op.product_id: normalized_qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.product_qty, op.product_id.uom_id.id) _create_link_for_product(op.product_id.id, normalized_qty) + elif op.package_id: + for product_id, qty in package_obj._get_all_products_quantities(cr, uid, op.package_id.id, context=context).items(): + _create_link_for_product(product_id, qty) 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 @@ -1040,13 +1015,12 @@ class stock_picking(osv.osv): if not context: context = {} stock_move_obj = self.pool.get('stock.move') - pack_obj = self.pool.get('stock.quant.package') - quant_obj = self.pool.get('stock.quant') for picking in self.browse(cr, uid, picking_ids, context=context): if not picking.pack_operation_ids: self.action_done(cr, uid, [picking.id], context=context) continue else: + self.do_recompute_remaining_quantities(cr, uid, [picking.id], context=context) #create extra moves in the picking (unexpected product moves coming from pack operations) self._create_extra_moves(cr, uid, picking, context=context) picking.refresh() @@ -1061,6 +1035,7 @@ class stock_picking(osv.osv): todo_move_ids.append(move.id) elif move.remaining_qty > 0: new_move = stock_move_obj.split(cr, uid, move, move.remaining_qty, context=context) + todo_move_ids.append(move.id) #Assign move as it was assigned before toassign_move_ids.append(new_move) else: @@ -1069,14 +1044,6 @@ class stock_picking(osv.osv): self.rereserve_quants(cr, uid, picking, move_ids=todo_move_ids, 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) - #Packing: - for ops in picking.pack_operation_ids: - if ops.result_package_id: - if ops.package_id: - pack_obj.write(cr, uid, [ops.package_id.id], {'parent_id': ops.result_package_id.id}, context=context) - else: - for record in ops.linked_move_operation_ids: - quant_obj.write(cr, uid, [q.id for q in record.move_id.quant_ids], {'package_id': ops.result_package_id.id}, context=context) elif context.get('do_only_split'): context.update({'split': todo_move_ids}) picking.refresh() @@ -1401,9 +1368,7 @@ class stock_move(osv.osv): ids_to_free = [] quant_obj = self.pool.get("stock.quant") for move in self.browse(cr, uid, move_ids, context=context): - ids_to_free += [quant.id for quant in move.reserved_quant_ids] - if ids_to_free: - quant_obj.write(cr, SUPERUSER_ID, ids_to_free, {'reservation_id': False}, context=context) + quant_obj.quants_unreserve(cr, uid, move, 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 "/") @@ -1620,7 +1585,7 @@ class stock_move(osv.osv): """ if not date_expected: date_expected = time.strftime('%Y-%m-%d %H:%M:%S') - return {'value':{'date': date_expected}} + return {'value': {'date': date_expected}} def action_confirm(self, cr, uid, ids, context=None): """ Confirms stock move or put it in waiting if it's linked to another move. @@ -1653,8 +1618,8 @@ class stock_move(osv.osv): """ Changes the state to assigned. @return: True """ - done = self.action_assign(cr, uid, ids, context=context) - self.write(cr, uid, list(set(ids) - set(done)), {'state': 'assigned'}) + self.action_assign(cr, uid, ids, context=context) + self.write(cr, uid, ids, {'state': 'assigned'}) return True def cancel_assign(self, cr, uid, ids, context=None): @@ -1677,10 +1642,6 @@ class stock_move(osv.osv): done.append(move.id) continue else: - qty_already_assigned = sum([q.qty for q in move.reserved_quant_ids]) - qty = move.product_qty - qty_already_assigned - #we keep the quants already assigned and try to find the remaining quantity on quants not assigned only - domain = [('reservation_id', '=', False), ('qty', '>', 0)] #build the prefered domain based on quants that moved in previous linked done move prev_quant_ids = [] for m2 in move.move_orig_ids: @@ -1688,15 +1649,23 @@ class stock_move(osv.osv): prev_quant_ids.append(q.id) prefered_domain = prev_quant_ids and [('id', 'in', prev_quant_ids)] or [] fallback_domain = prev_quant_ids and [('id', 'not in', prev_quant_ids)] or [] - quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=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) - #Will only reserve physical quants, no negative - quant_obj.quants_reserve(cr, uid, quants, move, context=context) - # the total quantity is provided by existing quants - if all(map(lambda x: x[0], quants)): - done.append(move.id) - self.write(cr, uid, done, {'state': 'assigned'}, context=context) + #we always keep the quants already assigned and try to find the remaining quantity on quants not assigned only + main_domain = [('reservation_id', '=', False), ('qty', '>', 0)] + #first try to find quants based on specific domains given by linked operations + for record in move.linked_move_operation_ids: + domain = main_domain + self.pool.get('stock.move.operation.link').get_specific_domain(cr, uid, record, context=context) + qty_already_assigned = sum([q.qty for q in record.reserved_quant_ids]) + qty = record.qty - qty_already_assigned + quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=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, record, context=context) + #then if the move isn't totally assigned, try to find quants without any specific domain + if move.state != 'assigned': + qty_already_assigned = sum([q.qty for q in move.reserved_quant_ids]) + qty = move.product_qty - qty_already_assigned + 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) - return done def action_cancel(self, cr, uid, ids, context=None): """ Cancels the moves and if all moves are cancelled it cancels the picking. @@ -1730,6 +1699,7 @@ class stock_move(osv.osv): """ context = context or {} 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"] if todo: self.action_confirm(cr, uid, todo, context=context) @@ -1740,13 +1710,27 @@ class stock_move(osv.osv): if move.picking_id: pickings.add(move.picking_id.id) qty = move.product_qty - - dom = [('qty', '>', 0)] + main_domain = [('qty', '>', 0)] prefered_domain = [('reservation_id', '=', move.id)] fallback_domain = [('reservation_id', '=', False)] - quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=dom, prefered_domain=prefered_domain, fallback_domain=fallback_domain, context=context) - #Will move all quants_get and as such create negative quants - quant_obj.quants_move(cr, uid, quants, move, context=context) + #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: + 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) + 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 + #but for operations having only result_package_id, we will create new quants in the final package directly + package_id = record.operation_id.result_package_id.id or False + quant_obj.quants_move(cr, uid, quants, move, lot_id=record.operation_id.lot_id.id, owner_id=record.operation_id.owner_id.id, src_package_id=record.operation_id.package_id.id, dest_package_id=package_id, context=context) + #packaging process + pack_op_obj.process_packaging(cr, uid, record.operation_id, quants, context=context) + 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) + #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 @@ -3092,7 +3076,7 @@ class stock_pack_operation(osv.osv): def _get_remaining_prod_quantities(self, cr, uid, operation, context=None): '''Get the remaining quantities per product on an operation with a package. This function returns a dictionary''' #if the operation doesn't concern a package, it's not relevant to call this function - if not operation.package_id: + if not operation.package_id or operation.product_id: return {operation.product_id.id: operation.remaining_qty} #get the total of products the package contains res = self.pool.get('stock.quant.package')._get_all_products_quantities(cr, uid, operation.package_id.id, context=context) @@ -3107,17 +3091,20 @@ class stock_pack_operation(osv.osv): uom_obj = self.pool.get('product.uom') res = {} for ops in self.browse(cr, uid, ids, context=context): + res[ops.id] = 0 if ops.package_id: #dont try to compute the remaining quantity for packages because it's not relevant (a package could include different products). #should use _get_remaining_prod_quantities instead - res[ops.id] = 0 continue - elif ops.product_id and ops.product_uom_id: - qty = uom_obj._compute_qty(cr, uid, ops.product_uom_id.id, ops.product_qty, ops.product_id.uom_id.id) + elif ops.product_id: + qty = ops.product_qty + if ops.product_uom_id: + qty = uom_obj._compute_qty(cr, uid, ops.product_uom_id.id, ops.product_qty, ops.product_id.uom_id.id) for record in ops.linked_move_operation_ids: qty -= record.qty #converting the remaining quantity in the pack operation UoM - qty = uom_obj._compute_qty(cr, uid, ops.product_id.uom_id.id, qty, ops.product_uom_id.id) + if ops.product_uom_id: + qty = uom_obj._compute_qty(cr, uid, ops.product_id.uom_id.id, qty, ops.product_uom_id.id) res[ops.id] = qty return res @@ -3171,20 +3158,22 @@ class stock_pack_operation(osv.osv): 'date': fields.date.context_today, } - def _get_domain(self, cr, uid, ops, context=None): - ''' - Gives domain for different - ''' - res = [] - if ops.package_id: - res.append(('package_id', '=', ops.package_id.id), ) - if ops.lot_id: - res.append(('lot_id', '=', ops.lot_id.id), ) - if ops.owner_id: - res.append(('owner_id', '=', ops.owner_id.id), ) - else: - res.append(('owner_id', '=', False), ) - return res + def process_packaging(self, cr, uid, operation, quants, context=None): + ''' Process the packaging of a given operation, after the quants have been moved. If there was not enough quants found + a quant already has been with the good package information so we don't consider that case in this method''' + quant_obj = self.pool.get("stock.quant") + pack_obj = self.pool.get("stock.quant.package") + for quant, qty in quants: + 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) + 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) + + + #TODO: this function can be refactored def _search_and_increment(self, cr, uid, picking_id, key, context=None): @@ -3242,8 +3231,28 @@ class stock_move_operation_link(osv.osv): 'qty': fields.float('Quantity', help="Quantity of products to consider when talking about the contribution of this pack operation towards the remaining quantity of the move (and inverse). Given in the product main uom."), 'operation_id': fields.many2one('stock.pack.operation', 'Operation', required=True, ondelete="cascade"), 'move_id': fields.many2one('stock.move', 'Move', required=True, ondelete="cascade"), + 'reserved_quant_ids': fields.one2many('stock.quant', 'link_move_operation_id', 'Reserved quants'), } + def get_specific_domain(self, cr, uid, record, context=None): + '''Returns the specific domain to consider for quant selection in action_assign() or action_done() of stock.move, + having the record given as parameter making the link between the stock move and a pack operation''' + package_obj = self.pool.get('stock.quant.package') + + op = record.operation_id + domain = [] + if op.package_id: + domain.append(('id', 'in', package_obj.get_content(cr, uid, [op.package_id.id], context=context))) + if op.quant_id: + domain.append(('id', '=', op.quant_id.id)) + if op.lot_id: + domain.append(('lot_id', '=', op.lot_id.id)) + if op.owner_id: + domain.append(('owner_id', '=', op.owner_id.id)) + else: + domain.append(('owner_id', '=', False)) + return domain + class stock_warehouse_orderpoint(osv.osv): """ Defines Minimum stock rules. diff --git a/addons/stock/test/packing.yml b/addons/stock/test/packing.yml index fc2015a8739..4978d44750e 100644 --- a/addons/stock/test/packing.yml +++ b/addons/stock/test/packing.yml @@ -51,14 +51,6 @@ stock_pack.write(cr, uid, record.pack_operation_ids[0].id, {'result_package_id': package1, 'product_qty': 120}) new_pack1 = stock_pack.create(cr, uid, {'product_id': ref('product1'), 'product_uom_id': ref('product.product_uom_unit'), 'picking_id': ref('pick1'), 'lot_id': lot_a, 'result_package_id': package2, 'product_qty': 120}, context=context) new_pack2 = stock_pack.create(cr, uid, {'product_id': ref('product1'), 'product_uom_id': ref('product.product_uom_unit'), 'picking_id': ref('pick1'), 'result_package_id': package3, 'product_qty': 60}, context=context) -- - Use button rereserve and check the qtyremaining on the moves are correct (=original quantities) -- - !python {model: stock.picking}: | - self.rereserve(cr, uid, [ref('pick1')], context=context) - picking = self.browse(cr, uid, ref('pick1'), context=context) - move_reco = picking.move_lines[0] - assert move_reco.remaining_qty == 300.0, "Remaining quantities should not change upon receiving" - Transfer the reception - @@ -114,9 +106,9 @@ for rec in delivery_id.pack_operation_ids: if rec.package_id.name == 'Pallet 2': lot_ids = self.pool.get("stock.production.lot").search(cr, uid, [('product_id', '=', ref('product1')), ('name','=','Lot A')]) - stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product1'), 'product_qty': 20, 'lot_id': lot_ids[0]}, context=context) + stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product1'), 'product_qty': 20, 'lot_id': lot_ids[0], 'package_id': False, 'product_uom_id': ref('product.product_uom_unit')}, context=context) if rec.package_id.name == 'Pallet 3': - stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product1'),'product_qty': 10}, context=context) + stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product1'),'product_qty': 10, 'product_uom_id': ref('product.product_uom_unit')}, context=context) - Process this picking - @@ -141,24 +133,15 @@ else: assert False, "Unrecognized quant" - - Check a backorder was created and on that backorder, prepare partial + Check a backorder was created and on that backorder, prepare partial and process backorder - !python {model: stock.picking}: | - picking = self.browse(cr, uid, ref('delivery_order1'), context=context) - backorder = self.search(cr, uid, [('backorder_id.id', '=', picking.id)], context=context) - assert backorder, "Backorder should have been created" - backorder_id = self.browse(cr, uid, backorder, context=context) - self.do_prepare_partial(cr, uid, backorder, context=context) - stock_pack = self.pool.get('stock.pack.operation').create(cr, uid, {'picking_id': backorder_id[0].id, 'product_qty': 20}) -- - Process this backorder -- - !python {model: stock.picking}: | - picking = self.browse(cr, uid, ref('delivery_order1'), context=context) - backorder = self.search(cr, uid, [('backorder_id.id', '=', picking.id)], context=context) - backorder_id = self.browse(cr, uid, backorder, context=context) - self.rereserve(cr, uid, [backorder_id[0].id], context=context) - self.do_transfer(cr, uid, [backorder_id[0].id], context=context) + backorder_ids = self.search(cr, uid, [('backorder_id', '=', ref('delivery_order1'))], context=context) + assert backorder_ids, "Backorder should have been created" + self.do_prepare_partial(cr, uid, backorder_ids, context=context) + stock_pack = self.pool.get('stock.pack.operation').create(cr, uid, {'picking_id': backorder_ids[0], 'product_qty': 20}) + self.action_assign(cr, uid, backorder_ids, context=context) + self.do_transfer(cr, uid, backorder_ids, context=context) - Check there are still 0 pieces in stock - diff --git a/addons/stock/test/packingneg.yml b/addons/stock/test/packingneg.yml index 77080fdec9c..5f26c2f59ac 100644 --- a/addons/stock/test/packingneg.yml +++ b/addons/stock/test/packingneg.yml @@ -84,9 +84,9 @@ for rec in delivery_id.pack_operation_ids: if rec.package_id.name == 'Palneg 2': lot_ids = self.pool.get("stock.production.lot").search(cr, uid, [('product_id', '=', ref('product_neg')), ('name','=','Lot neg')]) - stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product_neg'), 'product_qty': 140, 'lot_id': lot_ids[0]}, context=context) + stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product_neg'), 'product_qty': 140, 'lot_id': lot_ids[0], 'product_uom_id': ref('product.product_uom_unit')}, context=context) if rec.package_id.name == 'Palneg 3': - stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product_neg'),'product_qty': 10}, context=context) + stock_pack.write(cr, uid, [rec.id], {'product_id': ref('product_neg'),'product_qty': 10, 'product_uom_id': ref('product.product_uom_unit')}, context=context) - Process this picking -