From fec027e83203e6705f690469cd39101e4eba3b06 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 15 Jan 2013 11:40:15 +0100 Subject: [PATCH 01/22] [IMP] reorder modules menus bzr revid: chs@openerp.com-20130115104015-5ytx00t0b5230aaf --- openerp/addons/base/module/module_view.xml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/openerp/addons/base/module/module_view.xml b/openerp/addons/base/module/module_view.xml index 3a43a2591ba..3923c9de3bd 100644 --- a/openerp/addons/base/module/module_view.xml +++ b/openerp/addons/base/module/module_view.xml @@ -171,23 +171,18 @@ - - Modules ir.module.module form kanban,tree,form -

No module found!

You should try others search criteria.

- + @@ -195,20 +190,14 @@ Apps apps - - + Updates apps.updates {} - - + From 7e1a76cdd846a8c455d402fcd76d8baa58a9b2f8 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 15 Jan 2013 11:40:47 +0100 Subject: [PATCH 02/22] [FIX] setup.py: correct windows install bzr revid: chs@openerp.com-20130115104047-6hrl825bn5pkmoo6 --- setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup.py b/setup.py index b144924d022..e4e6001d302 100755 --- a/setup.py +++ b/setup.py @@ -43,6 +43,12 @@ def data(): base = os.path.join('pytz', root[len(tzdir) + 1:]) r[base] = [os.path.join(root, f) for f in filenames] + import docutils + dudir = os.path.dirname(docutils.__file__) + for root, _, filenames in os.walk(dudir): + base = os.path.join('docutils', root[len(dudir) + 1:]) + r[base] = [os.path.join(root, f) for f in filenames if not f.endswith(('.py', '.pyc', '.pyo'))] + return r.items() def gen_manifest(): From e2639618f666605e385befb578db3f889a8c035f Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 17 Jan 2013 10:27:22 +0100 Subject: [PATCH 03/22] [DOC] remove openerpdev intersphinx, add ref to module doc bzr revid: xmo@openerp.com-20130117092722-6rfhkcu4igrgeo06 --- addons/web/doc/conf.py | 1 - addons/web/doc/module.rst | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/web/doc/conf.py b/addons/web/doc/conf.py index 54434190707..7fe38022ab1 100644 --- a/addons/web/doc/conf.py +++ b/addons/web/doc/conf.py @@ -253,6 +253,5 @@ todo_include_todos = True intersphinx_mapping = { 'python': ('http://docs.python.org/', None), 'openerpserver': ('http://doc.openerp.com/trunk/developers/server', None), - 'openerpdev': ('http://doc.openerp.com/trunk/developers', None), 'openerpcommand': ('http://doc.openerp.com/trunk/developers/command', None), } diff --git a/addons/web/doc/module.rst b/addons/web/doc/module.rst index 1bdb7c14799..8306e885f65 100644 --- a/addons/web/doc/module.rst +++ b/addons/web/doc/module.rst @@ -1,3 +1,5 @@ +.. _module: + Building an OpenERP Web module ============================== From 3574038ffdf78e8c63430ecc92a4f2d916207fda Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 17 Jan 2013 14:29:24 +0100 Subject: [PATCH 04/22] [FIX] apps: install_from_url: fix install condition + better logging bzr revid: chs@openerp.com-20130117132924-ejzbkh5przqi6hwf --- openerp/addons/base/module/module.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 9e8b68451c5..123bf4124ed 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2004-2012 OpenERP S.A. (). +# Copyright (C) 2004-2013 OpenERP S.A. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -656,6 +656,7 @@ class module(osv.osv): def install_from_urls(self, cr, uid, urls, context=None): OPENERP = 'openerp' tmp = tempfile.mkdtemp() + _logger.debug('Install from url: %r', urls) try: # 1. Download & unzip missing modules for module_name, url in urls.items(): @@ -672,12 +673,13 @@ class module(osv.osv): zipfile.ZipFile(StringIO(content)).extractall(tmp) assert os.path.isdir(os.path.join(tmp, module_name)) - # 2a. Copy/Replace module source in addons path + # 2a. Copy/Replace module source in addons path for module_name, url in urls.items(): if module_name == OPENERP or not url: continue # OPENERP is special case, handled below, and no URL means local module module_path = modules.get_module_path(module_name, downloaded=True, display_warning=False) bck = backup(module_path, False) + _logger.info('Copy downloaded module `%s` to `%s`', module_name, module_path) shutil.move(os.path.join(tmp, module_name), module_path) if bck: shutil.rmtree(bck) @@ -697,15 +699,22 @@ class module(osv.osv): # then replace the server by the new "base" module server_dir = openerp.tools.config['root_path'] # XXX or dirname() bck = backup(server_dir) + _logger.info('Copy downloaded module `openerp` to `%s`', server_dir) shutil.move(os.path.join(tmp, OPENERP), server_dir) #if bck: # shutil.rmtree(bck) self.update_list(cr, uid, context=context) - ids = self.search(cr, uid, [('name', 'in', urls.keys())], context=context) - if self.search_count(cr, uid, [('id', 'in', ids), ('state', '=', 'installed')], context=context): - # if any to update + with_urls = [m for m, u in urls.items() if u] + downloaded_ids = self.search(cr, uid, [('name', 'in', with_urls)], context=context) + already_installed = self.search(cr, uid, [('id', 'in', downloaded_ids), ('state', '=', 'installed')], context=context) + + to_install_ids = self.search(cr, uid, [('name', 'in', urls.keys()), ('state', '=', 'uninstalled')], context=context) + post_install_action = self.button_immediate_install(cr, uid, to_install_ids, context=context) + + if already_installed: + # in this case, force server restart to reload python code... cr.commit() openerp.service.restart_server() return { @@ -713,7 +722,7 @@ class module(osv.osv): 'tag': 'home', 'params': {'wait': True}, } - return self.button_immediate_install(cr, uid, ids, context=context) + return post_install_action finally: shutil.rmtree(tmp) From 4857a8a020d81ebd375122fb478726103c3f2393 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 17 Jan 2013 14:51:08 +0100 Subject: [PATCH 05/22] [FIX] module loading: call adapt_version() instead of computing it ourself bzr revid: chs@openerp.com-20130117135108-a4wt4wtbtfdwiui3 --- openerp/modules/loading.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index fb68642f137..638a40c9fa8 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2012 OpenERP s.a. (). +# Copyright (C) 2010-2013 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -36,14 +36,12 @@ import openerp.modules.graph import openerp.modules.migration import openerp.osv as osv import openerp.pooler as pooler -import openerp.release as release import openerp.tools as tools from openerp import SUPERUSER_ID -from openerp import SUPERUSER_ID from openerp.tools.translate import _ from openerp.modules.module import initialize_sys_path, \ - load_openerp_module, init_module_models + load_openerp_module, init_module_models, adapt_version _logger = logging.getLogger(__name__) @@ -213,7 +211,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= migrations.migrate_module(package, 'post') - ver = release.major_version + '.' + package.data['version'] + ver = adapt_version(package.data['version']) # Set new modules and dependencies modobj.write(cr, SUPERUSER_ID, [module_id], {'state': 'installed', 'latest_version': ver}) # Update translations for all installed languages From 3e3edf0ce3ed514c57f700780464d1850e0e4acd Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 17 Jan 2013 18:58:09 +0100 Subject: [PATCH 07/22] [FIX] web_analytics: track pageview bzr revid: chs@openerp.com-20130117175809-ztptqe9y756hx8kk --- addons/web_analytics/static/src/js/web_analytics.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/web_analytics/static/src/js/web_analytics.js b/addons/web_analytics/static/src/js/web_analytics.js index 26171cb32aa..6e977c5465b 100644 --- a/addons/web_analytics/static/src/js/web_analytics.js +++ b/addons/web_analytics/static/src/js/web_analytics.js @@ -142,6 +142,7 @@ openerp.web_analytics = function(instance) { 'action': state.view_type, 'label': url, }); + this._push_pageview(url); } }, /* @@ -187,6 +188,7 @@ openerp.web_analytics = function(instance) { 'action': action.name || action.tag, 'label': url, }); + t._push_pageview(url); return this._super.apply(this, arguments); }, }); From d5673e4c33474056de9109cb9be7b7ddf3a143c5 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 7 Mar 2014 14:51:17 +0100 Subject: [PATCH 09/22] [IMP] Take location from pack operations when possible, otherwise use move location_id in get preferred bzr revid: jco@openerp.com-20140307135117-hqeja9stlakkx3cw --- addons/stock/stock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 7a1a2b2715e..1434a546485 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1936,7 +1936,7 @@ class stock_move(osv.osv): domain = main_domain[move.id] + 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=[], fallback_domain=[], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context) + quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id or move.location_id, move.product_id, qty, domain=domain, prefered_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) for move in todo_moves: @@ -2016,7 +2016,7 @@ class stock_move(osv.osv): fallback_domain = [('reservation_id', '=', False)] self.check_tracking(cr, uid, move, ops.package_id.id or ops.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, + quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id or 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: From 38afcf4d61ca18920eeec33d1cdc9db227ed42e9 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 11 Mar 2014 14:31:09 +0100 Subject: [PATCH 10/22] [REF] stock: refactoring of do_prepare_partial bzr revid: qdp-launchpad@openerp.com-20140311133109-e07mnhy4iaqm63in --- addons/stock/stock.py | 321 ++++++++++++++++-------------------- addons/stock/stock_demo.yml | 6 + 2 files changed, 152 insertions(+), 175 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 1434a546485..003c6cdc910 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -322,11 +322,12 @@ class stock_quant(osv.osv): if move.reserved_availability == move.product_qty and move.state in ('confirmed', 'waiting'): 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, src_package_id=False, dest_package_id=False, location_dest_id = False, context=None): - """Moves all given stock.quant in the destination location of the given move. + def quants_move(self, cr, uid, quants, move, location_to, 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. :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 :param lot_id: ID of the lot that must be set on the quants to move :param owner_id: ID of the partner that must own the quants to move :param src_package_id: ID of the package that contains the quants to move @@ -335,11 +336,9 @@ class stock_quant(osv.osv): 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, src_package_id=src_package_id, dest_package_id=dest_package_id, force_location = location_dest_id, context=context) - if not location_dest_id: - location_dest_id = move.location_dest_id - self.move_single_quant_tuple(cr, uid, quant, qty, move, location_dest_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, force_location=location_to, context=context) + self.move_single_quant(cr, uid, quant, location_to, qty, move, context=context) + self._quant_reconcile_negative(cr, uid, quant, move, context=context) def move_single_quant(self, cr, uid, quant, location_to, qty, move, context=None): '''Moves the given 'quant' in 'location_to' for the given 'qty', and logs the stock.move that triggered this move in the quant history. @@ -362,19 +361,6 @@ class stock_quant(osv.osv): quant.refresh() return new_quant - def move_single_quant_tuple(self, cr, uid, quant, qty, move, location_dest_id, context=None): - '''Effectively process the move of a tuple (quant record, qty to move). This may result in several quants moved - if the preferred locations on the move say so but by default it will only move the quant record given as argument - :param quant: browse record (stock.quant) - :param qty: float - :param move: browse record (stock.move) - ''' - if not quant: - return True - new_quant = self.move_single_quant(cr, uid, quant, location_dest_id, qty, move, context=context) - self._quant_reconcile_negative(cr, uid, quant, move, context=context) - quant = new_quant - def quants_get_prefered_domain(self, cr, uid, location, product, qty, domain=None, prefered_domain=False, fallback_domain=False, restrict_lot_id=False, restrict_partner_id=False, context=None): ''' This function tries to find quants in the given location for the given domain, by trying to first limit the choice on the quants that match the prefered_domain as well. But if the qty requested is not reached @@ -920,179 +906,167 @@ class stock_picking(osv.osv): self.action_assign(cr, uid, picking_ids, context=context) self.do_prepare_partial(cr, uid, picking_ids, context=context) - def _quant_putaway_apply(self, cr, uid, picking, quant, putaway, context=None): + def _picking_putaway_resolution(self, cr, uid, picking, product, putaway, context=None): if putaway.method == 'fixed' and putaway.location_spec_id: - return putaway.location_spec_id + return putaway.location_spec_id.id return False + def _get_top_level_packages(self, cr, uid, quants_suggested_locations, context=None): + """This method searches for the higher level packages that can be moved as a single operation, given a list of quants + to move and their suggested destination, and returns the list of matching packages. + """ + # Try to find as much as possible top-level packages that can be moved + pack_obj = self.pool.get("stock.quant.package") + quant_obj = self.pool.get("stock.quant") + top_lvl_packages = set() + quants_to_compare = [x.id for x in quants_suggested_locations.keys()] + for pack in list(set([x.package_id for x in quants_suggested_locations.keys() if x and x.package_id])): + loop = True + good_pack = False + test_pack = pack + while loop: + pack_quants = pack_obj.get_content(cr, uid, [test_pack.id], context=context) + pack_destination = False + all_in = True + for quant in quant_obj.browse(cr, uid, pack_quants, context=context): + # If the quant is not in the quants to compare and not in the common location + if not quant in quants_to_compare: + all_in = False + break + else: + #if putaway strat apply, the destination location of each quant may be different (and thus the package should not be taken as a single operation) + if not pack_destination: + pack_destination = quants_suggested_locations[quant] + elif pack_destination != quants_suggested_locations[quant]: + all_in = False + break + if all_in: + good_pack = test_pack.id + if test_pack.parent_id: + test_pack = test_pack.parent_id + else: + #stop the loop when there's no parent package anymore + loop = False + else: + #stop the loop when the package test_pack is not totally reserved for moves of this picking + #(some quants may be reserved for other picking or not reserved at all) + loop = False + if good_pack: + top_lvl_packages.add(good_pack) + return list(top_lvl_packages) - def _putaway_apply(self, cr, uid, picking, quants, qtys_remaining, context=None): + def _prepare_pack_ops(self, cr, uid, picking, quants, forced_qties, context=None): + """ returns a list of dict, ready to be used in create() of stock.pack.operation. + + :param picking: browse record (stock.picking) + :param quants: browse record list (stock.quant). List of quants associated to the picking + :param forced_qties: dictionary showing for each product (keys) its corresponding quantity (value) that is not covered by the quants associated to the picking """ - Apply putaway strategy to quants and remaining quantities - """ - product_putaway = {} - quant_dict = {} - for quant in quants: + def _picking_putaway_apply(product): location = False # Search putaway strategy - if product_putaway.get(quant.product_id.id): - putaway = product_putaway[quant.product_id.id] + if product_putaway_strats.get(product.id): + putaway_strat = product_putaway_strats[product.id] else: - putaway = self.pool.get('stock.location').get_putaway_strategy(cr, uid, picking.location_dest_id, quant.product_id, context=context) - product_putaway[quant.product_id.id] = putaway - if putaway: - location = self._quant_putaway_apply(cr, uid, picking, quant, putaway, context=context) - if location: - quant_dict[quant] = [(quant.qty, location,)] - if not location: - quant_dict[quant] = [(quant.qty, picking.location_dest_id,)] + putaway_strat = self.pool.get('stock.location').get_putaway_strategy(cr, uid, picking.location_dest_id, product, context=context) + product_putaway_strats[product.id] = putaway_strat + if putaway_strat: + location = self._picking_putaway_resolution(cr, uid, picking, product, putaway_strat, context=context) + return location or picking.picking_type_id.default_location_dest_id.id or picking.location_dest_id.id - remaining_dict = {} - for product in qtys_remaining.keys(): - location = False - if product_putaway.get(product): - putaway = product_putaway[product] + pack_obj = self.pool.get("stock.quant.package") + quant_obj = self.pool.get("stock.quant") + vals = [] + qtys_grouped = {} + #for each quant of the picking, find the suggested location + quants_suggested_locations = {} + product_putaway_strats = {} + for quant in quants: + if quant.qty <= 0: + continue + suggested_location_id = _picking_putaway_apply(quant.product_id) + quants_suggested_locations[quant] = suggested_location_id + + #find the packages we can movei as a whole + top_lvl_packages = self._get_top_level_packages(cr, uid, quants_suggested_locations, context=context) + # and then create pack operations for the top-level packages found + for pack in pack_obj.browse(cr, uid, top_lvl_packages, context=context): + pack_quants = pack_obj.get_content(cr, uid, [pack.id], context=context) + vals.append({ + 'picking_id': picking.id, + 'package_id': pack.id, + 'product_qty': 1.0, + 'location_id': pack.location_id.id, + 'location_dest_id': quants_suggested_locations[pack_quants[0]], + }) + #remove the quants inside the package so that they are excluded from the rest of the computation + for quant in quant_obj.browse(cr, uid, pack_quants, context=context): + del quants_suggested_locations[quant] + + # Go through all remaining reserved quants and group by product, package, lot, owner, source location and dest location + for quant, dest_location_id in quants_suggested_locations.items(): + key = (quant.product_id.id, quant.package_id.id, quant.lot_id.id, quant.owner_id.id, quant.location_id.id, dest_location_id) + if qtys_grouped.get(key): + qtys_grouped[key] += quant.qty else: - putaway = self.pool.get('stock.location').get_putaway_strategy(cr, uid, picking.location_dest_id, product, context=context) - product_putaway[product] = putaway - if putaway: - location = self._quant_putaway_apply(cr, uid, picking, False, putaway, context=context) - if location: - remaining_dict[product] = [(qtys_remaining[product], location,)] - if not location: - remaining_dict[product] = [(qtys_remaining[product], picking.location_dest_id,)] - return (quant_dict, remaining_dict,) + qtys_grouped[key] = quant.qty + + # Do the same for the forced quantities (in cases of force_assign or incomming shipment for example) + for product, qty in forced_qties.items(): + if qty <= 0: + continue + suggested_location_id = _picking_putaway_apply(product) + key = (product.id, False, False, False, picking.picking_type_id.default_location_src_id.id or picking.location_id.id, suggested_location_id) + if qtys_grouped.get(key): + qtys_grouped[key] += qty + else: + qtys_grouped[key] = qty + + # Create the necessary operations for the grouped quants and remaining qtys + for key, qty in qtys_grouped.items(): + vals.append({ + 'picking_id': picking.id, + 'product_qty': qty, + 'product_id': key[0], + 'package_id': key[1], + 'lot_id': key[2], + 'owner_id': key[3], + 'location_id': key[4], + 'location_dest_id': key[5], + 'product_uom_id': self.pool.get("product.product").browse(cr, uid, key[0], context=context).uom_id.id, + }) + return vals def do_prepare_partial(self, cr, uid, picking_ids, context=None): context = context or {} pack_operation_obj = self.pool.get('stock.pack.operation') - pack_obj = self.pool.get("stock.quant.package") - quant_obj = self.pool.get("stock.quant") + #pack_obj = self.pool.get("stock.quant.package") + #quant_obj = self.pool.get("stock.quant") - #get list of existing operations and delete them existing_package_ids = pack_operation_obj.search(cr, uid, [('picking_id', 'in', picking_ids)], context=context) if existing_package_ids: pack_operation_obj.unlink(cr, uid, existing_package_ids, context) for picking in self.browse(cr, uid, picking_ids, context=context): - reserved_move = {} - qtys_remaining = {} #Quantity remaining after calculating reserved quants - quants = [] + forced_qties = {} # Quantity remaining after calculating reserved quants + picking_quants = [] #Calculate packages, reserved quants, qtys of this picking's moves for move in picking.move_lines: - quants += move.reserved_quant_ids if move.state not in ('assigned', 'confirmed'): continue - reserved_move[move.id] = set([x.id for x in move.reserved_quant_ids]) - if move.state == 'assigned': - qty = move.product_qty - move.reserved_availability - else: - qty = 0 - - #Add qty to qtys remaining - if qtys_remaining.get(move.product_id): - qtys_remaining[move.product_id] += qty - else: - qtys_remaining[move.product_id] = qty - (putaway_quants_dict, putaway_remaining_dict) = self._putaway_apply(cr, uid, picking, quants, qtys_remaining, context=context) - packages = list(set([x.package_id for x in putaway_quants_dict.keys() if x and x.package_id])) - - # Try to find as much as possible top-level packages that can be moved - top_lvl_packages = set() - for pack in packages: - loop = True - good_pack = False - test_pack = pack - while loop: - quants = pack_obj.get_content(cr, uid, [test_pack.id], context=context) - quants_to_compare = putaway_quants_dict.keys() -# move_list = [m.id for m in picking.move_lines] - common_location = False - all_in = True - for quant in quant_obj.browse(cr, uid, quants, context=context): - # If the quant is not in the quants to compare and not in the common location - if not quant in quants_to_compare: - all_in = False - break - else: - for quants_tup in putaway_quants_dict[quant]: - if not common_location: - common_location = quants_tup[1] - elif common_location != quants_tup[1]: - all_in = False - break -# if not (quant in quants_to_compare and (not common_location or putaway_quants_dict[quant][1] == common_location)): -# all_in = False -# break -# elif not common_location and quant in quants_to_compare: -# common_location = putaway_quants_dict[quant][1] - if all_in: - good_pack = test_pack.id - if test_pack.parent_id: - test_pack = test_pack.parent_id - else: - #stop the loop when there's no parent package anymore - loop = False + move_quants = move.reserved_quant_ids + picking_quants += move_quants + forced_qty = (move.state == 'assigned') and move.product_qty - move.reserved_availability or 0 + #if we used force_assign() on the move, or if the move is incomming, forced_qty > 0 + if forced_qty: + if forced_qties.get(move.product_id): + forced_qties[move.product_id] += forced_qty else: - #stop the loop when the package test_pack is not totally reserved for moves of this picking - #(some quants may be reserved for other picking or not reserved at all) - loop = False - if good_pack: - top_lvl_packages.add(good_pack) - - # Create pack operations for the top-level packages found - for pack in pack_obj.browse(cr, uid, list(top_lvl_packages), context=context): - quants = pack_obj.get_content(cr, uid, [pack.id], context=context) - quant = quant_obj.browse(cr, uid, quants[0], context=context) - pack_operation_obj.create(cr, uid, { - 'picking_id': picking.id, - 'package_id': pack.id, - 'product_qty': 1.0, - 'location_id': pack.location_id.id, - 'location_dest_id': putaway_quants_dict[quant][0][1].id, - }, context=context) - for quant in quant_obj.browse(cr, uid, quants, context=context): - reserved_move[quant.reservation_id.id] -= set([quant.id]) - del putaway_quants_dict[quant] - qtys_remaining[quant.product_id] -= quant.qty - - - qtys_grouped = {} - # Go through all remaining reserved quants and group by product, package, lot, owner, source location and dest location - for quant in putaway_quants_dict.keys(): - for quant_tup in putaway_quants_dict[quant]: - if quant_tup[0] > 0: - key = (quant.product_id.id, quant.package_id.id, quant.lot_id.id, quant.owner_id.id, quant.location_id.id, quant_tup[1].id) - if qtys_grouped.get(key): - qtys_grouped[key] += quant_tup[0] - else: - qtys_grouped[key] = quant_tup[0] - - # Add remaining qtys (in cases of force_assign for example) - for product in putaway_remaining_dict.keys(): - for product_tup in putaway_remaining_dict[product]: - if product_tup[0] > 0: - key = (product.id, False, False, False, picking.location_id.id, product_tup[1].id) - if qtys_grouped.get(key): - qtys_grouped[key] += product_tup[0] - else: - qtys_grouped[key] = product_tup[0] - - # Create the necessary operations for the grouped quants and remaining qtys - for key, qty in qtys_grouped.items(): - pack_operation_obj.create(cr, uid, { - 'picking_id': picking.id, - 'product_qty': qty, - 'product_id': key[0], - 'package_id': key[1], - 'lot_id': key[2], - 'owner_id': key[3], - 'location_id': key[4], - 'location_dest_id': key[5], - 'product_uom_id': self.pool.get("product.product").browse(cr, uid, key[0], context=context).uom_id.id, - }, context=context) + forced_qties[move.product_id] = forced_qty + for vals in self._prepare_pack_ops(cr, uid, picking, picking_quants, forced_qties, context=context): + pack_operation_obj.create(cr, uid, vals, context=context) def do_unreserve(self, cr, uid, picking_ids, context=None): """ @@ -1626,8 +1600,6 @@ class stock_move(osv.osv): push_obj._apply(cr, uid, rule, move, context=context) return True - - def _create_procurement(self, cr, uid, move, context=None): """ This will create a procurement order """ return self.pool.get("procurement.order").create(cr, uid, self._prepare_procurement_from_move(cr, uid, move, context=context)) @@ -1936,7 +1908,7 @@ class stock_move(osv.osv): domain = main_domain[move.id] + 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, ops.location_id or move.location_id, move.product_id, qty, domain=domain, prefered_domain=[], fallback_domain=[], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context) + quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id, move.product_id, qty, domain=domain, prefered_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) for move in todo_moves: @@ -2016,14 +1988,14 @@ class stock_move(osv.osv): fallback_domain = [('reservation_id', '=', False)] self.check_tracking(cr, uid, move, ops.package_id.id or ops.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, ops.location_id or move.location_id, move.product_id, record.qty, domain=dom, prefered_domain=prefered_domain, + quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.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 #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=ops.lot_id.id, owner_id=ops.owner_id.id, src_package_id=ops.package_id.id, dest_package_id=package_id, location_dest_id = ops.location_dest_id, context=context) + quant_obj.quants_move(cr, uid, quants, move, ops.location_dest_id, lot_id=ops.lot_id.id, owner_id=ops.owner_id.id, src_package_id=ops.package_id.id, dest_package_id=package_id, context=context) #packaging process pack_op_obj.process_packaging(cr, uid, ops, [x[0].id for x in quants if x[0]], context=context) move_qty[move.id] -= record.qty @@ -2036,7 +2008,7 @@ class stock_move(osv.osv): self.check_tracking(cr, uid, move, move.restrict_lot_id.id, context=context) 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=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) + 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) @@ -3211,7 +3183,6 @@ class stock_location_path(osv.osv): - # ------------------------- # Packaging related stuff # ------------------------- @@ -3481,8 +3452,8 @@ class stock_pack_operation(osv.osv): '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'), - 'location_dest_id': fields.many2one('stock.location', 'Location To'), + 'location_id': fields.many2one('stock.location', 'Location From', required=True), + 'location_dest_id': fields.many2one('stock.location', 'Location To', required=True), } _defaults = { diff --git a/addons/stock/stock_demo.yml b/addons/stock/stock_demo.yml index a3a49ba1225..46427cb5e09 100644 --- a/addons/stock/stock_demo.yml +++ b/addons/stock/stock_demo.yml @@ -90,6 +90,8 @@ - product_id: product.product_product_6 product_qty: 100 product_uom_id: product.product_uom_unit + location_id: stock.stock_location_stock + location_dest_id: stock.stock_location_customers - !record {model: stock.picking, id: outgoing_shipment_main_warehouse2}: picking_type_id: stock.picking_type_out @@ -209,6 +211,8 @@ - product_id: product.product_product_48 product_qty: 100 product_uom_id: product.product_uom_unit + location_id: stock.stock_location_suppliers + location_dest_id: stock.stock_location_shop0 - !record {model: stock.picking, id: incomming_chicago_warehouse2}: picking_type_id: chi_picking_type_in @@ -264,6 +268,8 @@ - product_id: product.product_product_6 product_qty: 100 product_uom_id: product.product_uom_unit + location_id: stock.stock_location_shop0 + location_dest_id: stock.stock_location_customers - !record {model: stock.picking, id: outgoing_chicago_warehouse2}: picking_type_id: chi_picking_type_out From aed228331fe0af4004755a42e4d8cfe16d26737a Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 11 Mar 2014 16:44:09 +0100 Subject: [PATCH 11/22] [FIX] stock: do prepare partial bzr revid: qdp-launchpad@openerp.com-20140311154409-v5aoj3tx2frfi9jz --- addons/stock/stock.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 003c6cdc910..794958bf895 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -919,14 +919,14 @@ class stock_picking(osv.osv): pack_obj = self.pool.get("stock.quant.package") quant_obj = self.pool.get("stock.quant") top_lvl_packages = set() - quants_to_compare = [x.id for x in quants_suggested_locations.keys()] + quants_to_compare = quants_suggested_locations.keys() for pack in list(set([x.package_id for x in quants_suggested_locations.keys() if x and x.package_id])): loop = True - good_pack = False test_pack = pack + good_pack = False + pack_destination = False while loop: pack_quants = pack_obj.get_content(cr, uid, [test_pack.id], context=context) - pack_destination = False all_in = True for quant in quant_obj.browse(cr, uid, pack_quants, context=context): # If the quant is not in the quants to compare and not in the common location @@ -1156,6 +1156,8 @@ class stock_picking(osv.osv): todo_move_ids.append(move.id) #Assign move as it was assigned before toassign_move_ids.append(new_move) + else: + todo_move_ids.append(move.id) 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) @@ -1861,8 +1863,6 @@ class stock_move(osv.osv): context = context or {} quant_obj = self.pool.get("stock.quant") to_assign_moves = [] - prefered_domain = {} - fallback_domain = {} main_domain = {} todo_moves = [] operations = set() From 7d0760b59a21dddfcc8b2d49f7977190a8272e6b Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 11 Mar 2014 17:01:11 +0100 Subject: [PATCH 12/22] [FIX] stock: prepare partial when top_lvl_package is used bzr revid: qdp-launchpad@openerp.com-20140311160111-ed895thk06fg6da6 --- addons/stock/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 794958bf895..3db4d003b4c 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -997,7 +997,7 @@ class stock_picking(osv.osv): 'package_id': pack.id, 'product_qty': 1.0, 'location_id': pack.location_id.id, - 'location_dest_id': quants_suggested_locations[pack_quants[0]], + 'location_dest_id': quants_suggested_locations[quant_obj.browse(cr, uid, pack_quants[0], context=context)], }) #remove the quants inside the package so that they are excluded from the rest of the computation for quant in quant_obj.browse(cr, uid, pack_quants, context=context): From ff09748ec9eed3b2430f52ad723d947d6695475e Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 11 Mar 2014 18:14:43 +0100 Subject: [PATCH 13/22] [FIX] stock: shipment.yml fixed. The fields location_id and location_dest_id are now required on pack.operations bzr revid: qdp-launchpad@openerp.com-20140311171443-sbxsa2p8biyzo7t9 --- addons/stock/test/shipment.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/stock/test/shipment.yml b/addons/stock/test/shipment.yml index 5379cd8d4e0..585c2469108 100644 --- a/addons/stock/test/shipment.yml +++ b/addons/stock/test/shipment.yml @@ -19,6 +19,8 @@ 'product_id': ref('product_icecream'), 'product_uom_id': ref('product.product_uom_kgm'), 'product_qty': 40 + 'location_id': ref('stock.stock_location_suppliers'), + 'location_dest_id': ref('stock.stock_location_14') }) context.update({'active_model': 'stock.picking', 'active_id': ref('incomming_shipment'), 'active_ids': [ref('incomming_shipment')]}) pick.do_transfer(context=context) @@ -47,6 +49,8 @@ 'product_id': ref('product_icecream'), 'product_uom_id': ref('product.product_uom_kgm'), 'product_qty': 10 + 'location_id': ref('stock.stock_location_suppliers'), + 'location_dest_id': ref('stock.stock_location_14') }) backorder.do_transfer(context=context) - From bc616fce912773ff213e6ea812c99d3d91ff12b5 Mon Sep 17 00:00:00 2001 From: Cedric Snauwaert Date: Tue, 11 Mar 2014 18:45:05 +0100 Subject: [PATCH 14/22] [FIX]order stock_inventory_line by location name, product code, product name lp bug: https://launchpad.net/bugs/1087033 fixed bzr revid: ls@numerigraphe.com-20140311174505-p086c5nzvpifqxky --- addons/stock/stock.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 7198c89e286..e34fcb1adbe 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2867,6 +2867,14 @@ class stock_inventory_line(osv.osv): _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), @@ -2876,6 +2884,15 @@ class stock_inventory_line(osv.osv): 'company_id': fields.related('inventory_id','company_id',type='many2one',relation='res.company',string='Company',store=True, select=True, readonly=True), 'prod_lot_id': fields.many2one('stock.production.lot', 'Serial Number', domain="[('product_id','=',product_id)]"), 'state': fields.related('inventory_id','state',type='char',string='Status',readonly=True), + '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),}), } def _default_stock_location(self, cr, uid, context=None): From 0b5ca307d5c9a550bb8c2919ae53206fc94018da Mon Sep 17 00:00:00 2001 From: Lionel Sausin Date: Tue, 11 Mar 2014 19:12:36 +0100 Subject: [PATCH 15/22] [IMP] sort inventory lines on the name of serial numbers, not their ID bzr revid: ls@numerigraphe.com-20140311181236-o0pnweb0ze1efdwy --- addons/stock/stock.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index e34fcb1adbe..5cc0af224b9 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2867,13 +2867,16 @@ class stock_inventory_line(osv.osv): _name = "stock.inventory.line" _description = "Inventory Line" _rec_name = "inventory_id" - _order = "inventory_id, location_name, product_code, product_name, prod_lot_id" + _order = "inventory_id, location_name, product_code, product_name, prodlot_name" 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) + + def _get_prodlot_change(self, cr, uid, ids, context=None): + return self.pool.get('stock.inventory.line').search(cr, uid, [('prod_lot_id', 'in', ids)], context=context) _columns = { 'inventory_id': fields.many2one('stock.inventory', 'Inventory', ondelete='cascade', select=True), @@ -2893,6 +2896,9 @@ class stock_inventory_line(osv.osv): '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),}), + 'prodlot_name': fields.related('prod_lot_id', 'name', type='char', string='Serial Number name', store={ + 'stock.production.lot': (_get_prodlot_change, ['name'], 20), + 'stock.inventory.line': (lambda self, cr, uid, ids, c={}: ids, ['prod_lot_id'], 20),}), } def _default_stock_location(self, cr, uid, context=None): From fcf8d138063b37c193f5292c5ebbe5657b1907a5 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 12 Mar 2014 09:10:10 +0100 Subject: [PATCH 16/22] [FIX] stock: ... bzr revid: qdp-launchpad@openerp.com-20140312081010-x5oxh4te1xh0v3vv --- addons/stock/test/shipment.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/test/shipment.yml b/addons/stock/test/shipment.yml index 585c2469108..4e640f3aa64 100644 --- a/addons/stock/test/shipment.yml +++ b/addons/stock/test/shipment.yml @@ -18,7 +18,7 @@ 'picking_id': pick.id, 'product_id': ref('product_icecream'), 'product_uom_id': ref('product.product_uom_kgm'), - 'product_qty': 40 + 'product_qty': 40, 'location_id': ref('stock.stock_location_suppliers'), 'location_dest_id': ref('stock.stock_location_14') }) @@ -48,7 +48,7 @@ 'picking_id': backorder.id, 'product_id': ref('product_icecream'), 'product_uom_id': ref('product.product_uom_kgm'), - 'product_qty': 10 + 'product_qty': 10, 'location_id': ref('stock.stock_location_suppliers'), 'location_dest_id': ref('stock.stock_location_14') }) From 46c6aba808f57b67cc1490b9dea258f950b475ea Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 12 Mar 2014 10:57:11 +0100 Subject: [PATCH 17/22] [FIX] stock, packing.yml: location_id and location_dest_id are required bzr revid: qdp-launchpad@openerp.com-20140312095711-lyxfyda4nydd6twd --- addons/stock/test/packing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/test/packing.yml b/addons/stock/test/packing.yml index 3be5b9038c6..70e844ca4eb 100644 --- a/addons/stock/test/packing.yml +++ b/addons/stock/test/packing.yml @@ -49,8 +49,8 @@ #Create package for each line and assign it as result_package_id #create pack operation 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) + 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, 'location_id': ref('stock_location_suppliers'), 'location_dest_id': ref('stock_location_stock')}, 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, 'location_id': ref('stock_location_suppliers'), 'location_dest_id': ref('stock_location_stock')}, context=context) - Transfer the reception - From da1431f544a0f1b42337154387846b118bd5f0e6 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 12 Mar 2014 11:00:09 +0100 Subject: [PATCH 18/22] [FIX] stock, packingneg.yml: location_id and location_dest_id are required bzr revid: qdp-launchpad@openerp.com-20140312100009-u9b83h8bqzik2yx0 --- addons/stock/test/packingneg.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/test/packingneg.yml b/addons/stock/test/packingneg.yml index d42cbfa52e2..5bb93d44aca 100644 --- a/addons/stock/test/packingneg.yml +++ b/addons/stock/test/packingneg.yml @@ -49,8 +49,8 @@ #Create package for each line and assign it as result_package_id #create pack operation 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('product_neg'), 'product_uom_id': ref('product.product_uom_unit'), 'picking_id': ref('pick_neg'), 'lot_id': lot_a, 'result_package_id': package2, 'product_qty': 120}, context=context) - new_pack2 = stock_pack.create(cr, uid, {'product_id': ref('product_neg'), 'product_uom_id': ref('product.product_uom_unit'), 'picking_id': ref('pick_neg'), 'result_package_id': package3, 'product_qty': 60}, context=context) + new_pack1 = stock_pack.create(cr, uid, {'product_id': ref('product_neg'), 'product_uom_id': ref('product.product_uom_unit'), 'picking_id': ref('pick_neg'), 'lot_id': lot_a, 'result_package_id': package2, 'product_qty': 120, 'location_id': ref('stock_location_suppliers'), 'location_dest_id': ref('stock_location_stock')}, context=context) + new_pack2 = stock_pack.create(cr, uid, {'product_id': ref('product_neg'), 'product_uom_id': ref('product.product_uom_unit'), 'picking_id': ref('pick_neg'), 'result_package_id': package3, 'product_qty': 60, 'location_id': ref('stock_location_suppliers'), 'location_dest_id': ref('stock_location_stock')}, context=context) - Transfer the reception - From 5298db0f062f66f189fa2ba0128d05bd6c8993b7 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 12 Mar 2014 12:06:53 +0100 Subject: [PATCH 19/22] [FIX] sale_stock: location_id and location_dest_id are now required on stock.pack.operation bzr revid: qdp-launchpad@openerp.com-20140312110653-5dfjcmt9ahgu5ich --- addons/sale_stock/test/cancel_order_sale_stock.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/sale_stock/test/cancel_order_sale_stock.yml b/addons/sale_stock/test/cancel_order_sale_stock.yml index d9116d843f5..77508e28a2d 100644 --- a/addons/sale_stock/test/cancel_order_sale_stock.yml +++ b/addons/sale_stock/test/cancel_order_sale_stock.yml @@ -20,7 +20,9 @@ 'picking_id': pick.id, 'product_id': ref('product.product_product_27'), 'product_uom_id': ref('product.product_uom_unit'), - 'product_qty': 1 + 'product_qty': 1, + 'location_id': pick.location_id.id, + 'location_dest_id': pick.location_dest_id.id, }) pick.do_transfer(context=context) - From 6dae580a6b422d8d4955978fdb8505bbb5ba0b0e Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 12 Mar 2014 12:24:34 +0100 Subject: [PATCH 20/22] [IMP] stock: default location_id and location_dest_id for pack operations bzr revid: qdp-launchpad@openerp.com-20140312112434-nt2bc9wsb29dawom --- addons/stock/stock_view.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 02f4799a940..ede38e6058a 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -769,7 +769,7 @@