From b0c8e5eb9252160c0968379d78424c1fac47500d Mon Sep 17 00:00:00 2001 From: Mathieu Vatel Date: Wed, 7 Mar 2012 13:56:37 +0100 Subject: [PATCH 1/5] [ADD] stock_move_location --- stock_move_location/__init__.py | 25 +++ stock_move_location/__openerp__.py | 51 +++++ stock_move_location/i18n/fr.po | 143 ++++++++++++++ stock_move_location/stock.py | 182 ++++++++++++++++++ stock_move_location/stock_move_sequence.xml | 19 ++ stock_move_location/stock_view.xml | 67 +++++++ stock_move_location/wizard/__init__.py | 24 +++ stock_move_location/wizard/move_location.py | 46 +++++ .../wizard/move_location_view.xml | 34 ++++ 9 files changed, 591 insertions(+) create mode 100644 stock_move_location/__init__.py create mode 100644 stock_move_location/__openerp__.py create mode 100644 stock_move_location/i18n/fr.po create mode 100644 stock_move_location/stock.py create mode 100644 stock_move_location/stock_move_sequence.xml create mode 100755 stock_move_location/stock_view.xml create mode 100644 stock_move_location/wizard/__init__.py create mode 100644 stock_move_location/wizard/move_location.py create mode 100755 stock_move_location/wizard/move_location_view.xml diff --git a/stock_move_location/__init__.py b/stock_move_location/__init__.py new file mode 100644 index 00000000000..c2c2ebef6df --- /dev/null +++ b/stock_move_location/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +################################################################################# +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 Julius Network Solutions SARL +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +################################################################################# + +import stock +import wizard + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_move_location/__openerp__.py b/stock_move_location/__openerp__.py new file mode 100644 index 00000000000..abb62f76904 --- /dev/null +++ b/stock_move_location/__openerp__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +################################################################################# +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 Julius Network Solutions SARL +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +################################################################################# + +{ + "name" : "Move Stock Location", + "version" : "1.0", + "author" : "Julius Network Solutions,Odoo Community Association (OCA)", + "description" : """ + +Presentation: + +This module allows to move all stock in a stock location to an other one. +And adds fields and buttons to advance in Physical Inventories. + +""", + "website" : "http://www.julius.fr", + "depends" : [ + "stock", + "stock_barcode_reader", + ], + "category" : "Customs/Stock", + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + 'stock_view.xml', + 'stock_move_sequence.xml', + 'wizard/move_location_view.xml', + ], + 'test': [], + 'installable': True, + 'active': False, + 'certificate': '', +} diff --git a/stock_move_location/i18n/fr.po b/stock_move_location/i18n/fr.po new file mode 100644 index 00000000000..3c1f45c79ea --- /dev/null +++ b/stock_move_location/i18n/fr.po @@ -0,0 +1,143 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * stock_move_location +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.0.3\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2011-12-19 10:48+0000\n" +"PO-Revision-Date: 2011-12-19 10:48+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_move_location +#: field:stock.inventory,location_id:0 +msgid "Location" +msgstr "Stockage" + +#. module: stock_move_location +#: view:stock.inventory:0 +msgid "Start Acquisition" +msgstr "Demarrer la saisie" + +#. module: stock_move_location +#: view:stock.inventory:0 +msgid "Get Stock" +msgstr "Remplir" + +#. module: stock_move_location +#: view:stock.inventory:0 +msgid "Validate Move" +msgstr "Valider le transfert" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_fill_inventory +msgid "Import Inventory" +msgstr "Importer un inventaire" + +#. module: stock_move_location +#: code:addons/stock_move_location/stock.py:54 +#, python-format +msgid "Error !" +msgstr "Erreur !" + +#. module: stock_move_location +#: constraint:stock.move:0 +msgid "You try to assign a lot which is not from the same product" +msgstr "Vous essayez d'affecter un lot qui n'est pas pour le bon produit." + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_move +msgid "Stock Move" +msgstr "Transfert de Stock à Stock" + +#. module: stock_move_location +#: model:ir.module.module,description:stock_move_location.module_meta_information +msgid " This module allows to move all stock in a stock location to an other one " +msgstr " Ce module permet de déplacer tout le stock situé dans un ou plusieurs emplacement vers un autre emplacement " + +#. module: stock_move_location +#: field:stock.inventory,location_dest_id:0 +msgid "Destination Location" +msgstr "Emplacement de destination" + +#. module: stock_move_location +#: model:ir.actions.act_window,name:stock_move_location.action_move_stock_form +#: model:ir.ui.menu,name:stock_move_location.menu_action_move_stock_form +msgid "Move stock" +msgstr "Transfert de Stock à Stock" + +#. module: stock_move_location +#: code:addons/stock_move_location/stock.py:70 +#, python-format +msgid "Move" +msgstr "Transfert" + +#. module: stock_move_location +#: view:stock.inventory:0 +msgid "Confirm Inventory" +msgstr "Confirmer l'inventaire" + +#. module: stock_move_location +#: field:stock.inventory,comments:0 +msgid "Comments" +msgstr "Commentaires" + +#. module: stock_move_location +#: constraint:stock.move:0 +msgid "You must assign a production lot for this product" +msgstr "Vous devez affecter un lot de fabrication pour ce produit." + +#. module: stock_move_location +#: selection:stock.inventory,type:0 +msgid "Location Move" +msgstr "Transfert de Stock à Stock" + +#. module: stock_move_location +#: view:stock.inventory:0 +msgid "Move Stock" +msgstr "Transfert de Stock à Stock" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_inventory +#: selection:stock.inventory,type:0 +msgid "Inventory" +msgstr "Inventaire" + +#. module: stock_move_location +#: code:addons/stock_move_location/stock.py:54 +#, python-format +msgid "Please inform the destination of your move" +msgstr "S'il vous plaît informer la destination de votre transfert" + +#. module: stock_move_location +#: code:addons/stock_move_location/stock.py:70 +#, python-format +msgid "is done." +msgstr "est fait." + +#. module: stock_move_location +#: field:stock.inventory,type:0 +msgid "Type" +msgstr "Type" + +#. module: stock_move_location +#: model:ir.module.module,shortdesc:stock_move_location.module_meta_information +msgid "Move Stock Location" +msgstr "Tranfert de stock à stock" + +#. module: stock_move_location +#: model:ir.actions.act_window,help:stock_move_location.action_move_stock_form +msgid "You can use this to move a stock from a location to an other one." +msgstr "Vous pouvez l'utiliser pour passer d'un stockage vers un autre." + +#. module: stock_move_location +#: field:stock.move,pack_history_id:0 +msgid "History pack" +msgstr "Historique du colis" + diff --git a/stock_move_location/stock.py b/stock_move_location/stock.py new file mode 100644 index 00000000000..be0a5ae2ef0 --- /dev/null +++ b/stock_move_location/stock.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +################################################################################# +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 Julius Network Solutions SARL +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +################################################################################# + +from osv import fields, osv +from tools.translate import _ + +#class stock_fill_inventory(osv.osv_memory): +# _inherit = "stock.fill.inventory" +# def fill_inventory(self, cr, uid, ids, context=None): +# res = super(stock_fill_inventory, self).fill_inventory(cr, uid, ids, context=context) +# stock_inventory_obj = self.pool.get('stock.inventory') +# fill_inventory = self.browse(cr, uid, ids[0], context=context) +# if stock_inventory_obj.browse(cr, uid, context.get('active_id', False), context).location_id: +# stock_inventory_obj.write(cr, uid, context.get('active_id', False), {'location_id': fill_inventory.location_id.id}) +# return res +#stock_fill_inventory() + +class stock_inventory(osv.osv): + _inherit = "stock.inventory" + + _columns = { + 'type': fields.selection([('normal', 'Inventory'),('move', 'Location Move')], 'Type'), + 'location_id': fields.many2one('stock.location', 'Location'), + 'location_dest_id': fields.many2one('stock.location', 'Destination Location'), + 'comments':fields.text('Comments'), + } + + def get_sequence(self, cr , uid, context): + if context.get('type', False) == 'move': + return self.pool.get('ir.sequence').get(cr, uid, 'stock.inventory.move') or '/' + else: + return self.pool.get('ir.sequence').get(cr, uid, 'stock.inventory') or '/' + + _defaults = { + 'type': lambda *a: 'normal', + 'name': lambda x, y, z, c: x.get_sequence(y,z,c), + } + + def move_stock(self, cr, uid, ids, context=None): + if context is None: + context = {} + product_context = dict(context, compute_child=False) + + location_obj = self.pool.get('stock.location') + for inv in self.browse(cr, uid, ids, context=context): + if not inv.location_dest_id: + raise osv.except_osv(_('Error !'), _('Please inform the destination of your move')) + move_ids = [] + for line in inv.inventory_line_id: + location_id = inv.location_dest_id.id + date = line.date or inv.date + value = { + 'name': 'MOVE:' + str(line.inventory_id.id) + ':' + line.inventory_id.name, + 'product_id': line.product_id.id, + 'product_uom': line.product_uom.id, + 'prodlot_id': line.prod_lot_id.id, + 'date': date, + 'product_qty': line.product_qty, + 'location_id': line.location_id.id, + 'location_dest_id': location_id, + 'note': line.note or inv.comments or False, + } + move_ids.append(self._inventory_line_hook(cr, uid, line, value)) + message = _('Move') + " '" + inv.name + "' "+ _("is done.") + self.log(cr, uid, inv.id, message) + self.write(cr, uid, [inv.id], {'state': 'confirm', 'move_ids': [(6, 0, move_ids)]}) + return True + + def fill_inventory(self, cr, uid, ids, context=False): + res = {} + stock_fill_inventory_obj = self.pool.get('stock.fill.inventory') + inventory_data = self.browse(cr, uid, ids[0], context) + if context.get('type',[]) == 'move': + set_stock_zero = False + else: + set_stock_zero = True + if inventory_data.location_id: + context['location_id'] = inventory_data.location_id.id + fill_inventory_id = stock_fill_inventory_obj.create(cr, uid, { + 'location_id': inventory_data.location_id.id, + 'set_stock_zero': set_stock_zero}) + context_temp = context + context_temp['active_ids'] = [inventory_data.id] + context_temp['active_id'] = inventory_data.id + stock_fill_inventory_obj.fill_inventory(cr, uid, [fill_inventory_id], context_temp) + + + if context.get('type',[]) == 'move': + act = {} +# mod_obj = self.pool.get('ir.model.data') +# act_obj = self.pool.get('ir.actions.act_window') +# model_id = mod_obj.search(cr, uid, [('name', '=', 'move_stock_acquisition_link_2')])[0] +# act_id = mod_obj.read(cr, uid, model_id, ['res_id'])['res_id'] +# act = act_obj.read(cr, uid, act_id) + else: + mod_obj = self.pool.get('ir.model.data') + act_obj = self.pool.get('ir.actions.act_window') + model_id = mod_obj.search(cr, uid, [('name', '=', 'inventory_acquisition_link_1')])[0] + act_id = mod_obj.read(cr, uid, model_id, ['res_id'])['res_id'] + act = act_obj.read(cr, uid, act_id) + context = eval(act['context']) + context['default_inventory_id'] = inventory_data.id + context['default_name'] = inventory_data.name + act['context'] = context + return act + + +stock_inventory() + +class stock_move(osv.osv): + + _inherit = 'stock.move' + +# def _check_move(self, cr, uid, ids, context=None): +# """ Checks if the given production lot belong to a pack +# Return false if the production lot is in a pack +# """ +# production_lot_obj = self.pool.get('stock.production.lot') +# +# for move in self.browse(cr, uid, ids, context=context): +# if move.prodlot_id: +# if self.search(cr, uid, [('prodlot_id', '=', move.prodlot_id.id), ('state','not in',('cancel','done')), ('id', '!=', move.id)]): +# if move.prodlot_id.tracking_id: +# return False +# return True + + _columns = { + 'pack_history_id': fields.many2one('stock.tracking.history', 'History pack'), + } + +# _constraints =[ +# (_check_move, 'You try to assign a move to a lot which is already in a pack', ['prodlot_id']) +# ] + ''' Solution to move all pack and production lot if one in a pack is move ''' +# def move_parent(self, cr, uid, ids, context=None): +# """ Checks if the given production lot belong to a pack +# Move the pack in the same destination +# """ +# ''' variables ''' +# production_lot_obj = self.pool.get('stock.production.lot') +# move_packaging_obj = self.pool.get('stock.move.packaging') +# ''' init ''' +# if context == None: +# context = {} +# ''' process ''' +# for move in self.browse(cr, uid, ids, context=context): +# if move.prodlot_id: +# if move.prodlot_id.tracking_id: +# move_packaging_obj.move_pack(cr, uid, move.prodlot_id.tracking_id, context) +# return {} + +stock_move() + +class stock_inventory_line(osv.osv): + _inherit = "stock.inventory.line" + + _columns = { + 'date': fields.datetime('Date'), + 'note': fields.text('Notes'), + } + +stock_inventory_line() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_move_location/stock_move_sequence.xml b/stock_move_location/stock_move_sequence.xml new file mode 100644 index 00000000000..21d53d51a73 --- /dev/null +++ b/stock_move_location/stock_move_sequence.xml @@ -0,0 +1,19 @@ + + + + + + + Inventory Order + stock.inventory.move + + + + Inventory Order + stock.inventory.move + MOV + 3 + + + + diff --git a/stock_move_location/stock_view.xml b/stock_move_location/stock_view.xml new file mode 100755 index 00000000000..89ad954f3ad --- /dev/null +++ b/stock_move_location/stock_view.xml @@ -0,0 +1,67 @@ + + + + + + stock.inventory.tree + stock.inventory + tree + + + + + + + + + + stock.inventory.form + stock.inventory + form + + + + + + + + + + + + + + {'full':'1', 'type':'normal', 'default_type': 'normal'} + [('type', '=', 'normal')] + + + + [('state','=','draft'), ('type', '=', 'normal')] + + + + Move stock + ir.actions.act_window + stock.inventory + form + + {'full':'1', 'type':'move', 'default_type': 'move'} + [('type', '=', 'move')] + + You can use this to move a stock from a location to an other one. + + + + + + diff --git a/stock_move_location/wizard/__init__.py b/stock_move_location/wizard/__init__.py new file mode 100644 index 00000000000..4096c452a3f --- /dev/null +++ b/stock_move_location/wizard/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +################################################################################# +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 Julius Network Solutions SARL +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +################################################################################# + +import move_location + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_move_location/wizard/move_location.py b/stock_move_location/wizard/move_location.py new file mode 100644 index 00000000000..a27155d2a03 --- /dev/null +++ b/stock_move_location/wizard/move_location.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +################################################################################# +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 Julius Network Solutions SARL +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +################################################################################# + +from osv import fields, osv +from tools.translate import _ + +class stock_fill_inventory(osv.osv_memory): + _inherit = "stock.fill.inventory" + + def _get_location(self, cr, uid, active_id, context={}): + res = False + if active_id: + inv = self.pool.get('stock.inventory').browse(cr, uid, active_id) + if inv.location_id: + res = inv.location_id.id + return res + + _columns = { + 'location_id': fields.many2one('stock.location', 'Location', required=True), + } + + _defaults = { + 'location_id': lambda s,cr,uid,c: s._get_location(cr, uid, c.get('active_id',False), c), + } + +stock_fill_inventory() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_move_location/wizard/move_location_view.xml b/stock_move_location/wizard/move_location_view.xml new file mode 100755 index 00000000000..88c70a085b2 --- /dev/null +++ b/stock_move_location/wizard/move_location_view.xml @@ -0,0 +1,34 @@ + + + + + + + + From 9966b79867915fca28c3b82f717ad1543d73588e Mon Sep 17 00:00:00 2001 From: mpanarin Date: Thu, 27 Dec 2018 11:47:16 +0200 Subject: [PATCH 2/5] [MIG] 11.0 stock_move_location --- stock_move_location/README.rst | 21 ++ stock_move_location/__init__.py | 29 +-- stock_move_location/__manifest__.py | 23 +++ stock_move_location/__openerp__.py | 51 ----- .../data/stock_move_sequence.xml | 15 ++ stock_move_location/i18n/fr.po | 143 -------------- .../i18n/stock_move_location.pot | 117 +++++++++++ stock_move_location/models/__init__.py | 6 + stock_move_location/models/inventory_line.py | 47 +++++ stock_move_location/models/stock_inventory.py | 54 +++++ stock_move_location/readme/CONTRIBUTORS.rst | 2 + stock_move_location/readme/DESCRIPTION.rst | 1 + stock_move_location/readme/USAGE.rst | 9 + stock_move_location/stock.py | 182 ----------------- stock_move_location/stock_move_sequence.xml | 19 -- stock_move_location/stock_view.xml | 67 ------- stock_move_location/tests/__init__.py | 6 + stock_move_location/tests/test_common.py | 68 +++++++ .../tests/test_move_location.py | 154 +++++++++++++++ stock_move_location/views/stock_view.xml | 20 ++ stock_move_location/wizard/__init__.py | 28 +-- stock_move_location/wizard/move_location.py | 46 ----- .../wizard/move_location_view.xml | 34 ---- .../wizard/stock_move_location.py | 185 ++++++++++++++++++ .../wizard/stock_move_location.xml | 54 +++++ .../wizard/stock_move_location_line.py | 58 ++++++ 26 files changed, 850 insertions(+), 589 deletions(-) create mode 100644 stock_move_location/README.rst create mode 100644 stock_move_location/__manifest__.py delete mode 100644 stock_move_location/__openerp__.py create mode 100644 stock_move_location/data/stock_move_sequence.xml delete mode 100644 stock_move_location/i18n/fr.po create mode 100644 stock_move_location/i18n/stock_move_location.pot create mode 100644 stock_move_location/models/__init__.py create mode 100644 stock_move_location/models/inventory_line.py create mode 100644 stock_move_location/models/stock_inventory.py create mode 100644 stock_move_location/readme/CONTRIBUTORS.rst create mode 100644 stock_move_location/readme/DESCRIPTION.rst create mode 100644 stock_move_location/readme/USAGE.rst delete mode 100644 stock_move_location/stock.py delete mode 100644 stock_move_location/stock_move_sequence.xml delete mode 100755 stock_move_location/stock_view.xml create mode 100644 stock_move_location/tests/__init__.py create mode 100644 stock_move_location/tests/test_common.py create mode 100644 stock_move_location/tests/test_move_location.py create mode 100755 stock_move_location/views/stock_view.xml delete mode 100644 stock_move_location/wizard/move_location.py delete mode 100755 stock_move_location/wizard/move_location_view.xml create mode 100644 stock_move_location/wizard/stock_move_location.py create mode 100755 stock_move_location/wizard/stock_move_location.xml create mode 100644 stock_move_location/wizard/stock_move_location_line.py diff --git a/stock_move_location/README.rst b/stock_move_location/README.rst new file mode 100644 index 00000000000..21cd7854d5e --- /dev/null +++ b/stock_move_location/README.rst @@ -0,0 +1,21 @@ +**This file is going to be generated by oca-gen-addon-readme.** + +*Manual changes will be overwritten.* + +Please provide content in the ``readme`` directory: + +* **DESCRIPTION.rst** (required) +* INSTALL.rst (optional) +* CONFIGURE.rst (optional) +* **USAGE.rst** (optional, highly recommended) +* DEVELOP.rst (optional) +* ROADMAP.rst (optional) +* HISTORY.rst (optional, recommended) +* **CONTRIBUTORS.rst** (optional, highly recommended) +* CREDITS.rst (optional) + +Content of this README will also be drawn from the addon manifest, +from keys such as name, authors, maintainers, development_status, +and license. + +A good, one sentence summary in the manifest is also highly recommended. diff --git a/stock_move_location/__init__.py b/stock_move_location/__init__.py index c2c2ebef6df..5918b27a356 100644 --- a/stock_move_location/__init__.py +++ b/stock_move_location/__init__.py @@ -1,25 +1,6 @@ -# -*- coding: utf-8 -*- -################################################################################# -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2011 Julius Network Solutions SARL -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -################################################################################# +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -import stock -import wizard - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +from . import models +from . import wizard diff --git a/stock_move_location/__manifest__.py b/stock_move_location/__manifest__.py new file mode 100644 index 00000000000..4cf6ae6eca1 --- /dev/null +++ b/stock_move_location/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +{ + "name": "Move Stock Location", + "version": "11.0.1.0.0", + "author": "Julius Network Solutions, " + "Odoo Community Association (OCA)", + "summary": "This module allows to move all stock " + "in a stock location to an other one.", + "website": "https://github.com/OCA/stock-logistics-warehouse", + 'license': 'AGPL-3', + "depends": [ + "stock", + ], + "category": "Stock", + "data": [ + 'data/stock_move_sequence.xml', + 'views/stock_view.xml', + 'wizard/stock_move_location.xml', + ], +} diff --git a/stock_move_location/__openerp__.py b/stock_move_location/__openerp__.py deleted file mode 100644 index abb62f76904..00000000000 --- a/stock_move_location/__openerp__.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -################################################################################# -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2011 Julius Network Solutions SARL -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -################################################################################# - -{ - "name" : "Move Stock Location", - "version" : "1.0", - "author" : "Julius Network Solutions,Odoo Community Association (OCA)", - "description" : """ - -Presentation: - -This module allows to move all stock in a stock location to an other one. -And adds fields and buttons to advance in Physical Inventories. - -""", - "website" : "http://www.julius.fr", - "depends" : [ - "stock", - "stock_barcode_reader", - ], - "category" : "Customs/Stock", - "init_xml" : [], - "demo_xml" : [], - "update_xml" : [ - 'stock_view.xml', - 'stock_move_sequence.xml', - 'wizard/move_location_view.xml', - ], - 'test': [], - 'installable': True, - 'active': False, - 'certificate': '', -} diff --git a/stock_move_location/data/stock_move_sequence.xml b/stock_move_location/data/stock_move_sequence.xml new file mode 100644 index 00000000000..e27670c5dc5 --- /dev/null +++ b/stock_move_location/data/stock_move_sequence.xml @@ -0,0 +1,15 @@ + + + + + + Inventory Move + stock.inventory.move + MOV + 3 + 1 + 1 + + + + diff --git a/stock_move_location/i18n/fr.po b/stock_move_location/i18n/fr.po deleted file mode 100644 index 3c1f45c79ea..00000000000 --- a/stock_move_location/i18n/fr.po +++ /dev/null @@ -1,143 +0,0 @@ -# Translation of OpenERP Server. -# This file contains the translation of the following modules: -# * stock_move_location -# -msgid "" -msgstr "" -"Project-Id-Version: OpenERP Server 6.0.3\n" -"Report-Msgid-Bugs-To: support@openerp.com\n" -"POT-Creation-Date: 2011-12-19 10:48+0000\n" -"PO-Revision-Date: 2011-12-19 10:48+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: stock_move_location -#: field:stock.inventory,location_id:0 -msgid "Location" -msgstr "Stockage" - -#. module: stock_move_location -#: view:stock.inventory:0 -msgid "Start Acquisition" -msgstr "Demarrer la saisie" - -#. module: stock_move_location -#: view:stock.inventory:0 -msgid "Get Stock" -msgstr "Remplir" - -#. module: stock_move_location -#: view:stock.inventory:0 -msgid "Validate Move" -msgstr "Valider le transfert" - -#. module: stock_move_location -#: model:ir.model,name:stock_move_location.model_stock_fill_inventory -msgid "Import Inventory" -msgstr "Importer un inventaire" - -#. module: stock_move_location -#: code:addons/stock_move_location/stock.py:54 -#, python-format -msgid "Error !" -msgstr "Erreur !" - -#. module: stock_move_location -#: constraint:stock.move:0 -msgid "You try to assign a lot which is not from the same product" -msgstr "Vous essayez d'affecter un lot qui n'est pas pour le bon produit." - -#. module: stock_move_location -#: model:ir.model,name:stock_move_location.model_stock_move -msgid "Stock Move" -msgstr "Transfert de Stock à Stock" - -#. module: stock_move_location -#: model:ir.module.module,description:stock_move_location.module_meta_information -msgid " This module allows to move all stock in a stock location to an other one " -msgstr " Ce module permet de déplacer tout le stock situé dans un ou plusieurs emplacement vers un autre emplacement " - -#. module: stock_move_location -#: field:stock.inventory,location_dest_id:0 -msgid "Destination Location" -msgstr "Emplacement de destination" - -#. module: stock_move_location -#: model:ir.actions.act_window,name:stock_move_location.action_move_stock_form -#: model:ir.ui.menu,name:stock_move_location.menu_action_move_stock_form -msgid "Move stock" -msgstr "Transfert de Stock à Stock" - -#. module: stock_move_location -#: code:addons/stock_move_location/stock.py:70 -#, python-format -msgid "Move" -msgstr "Transfert" - -#. module: stock_move_location -#: view:stock.inventory:0 -msgid "Confirm Inventory" -msgstr "Confirmer l'inventaire" - -#. module: stock_move_location -#: field:stock.inventory,comments:0 -msgid "Comments" -msgstr "Commentaires" - -#. module: stock_move_location -#: constraint:stock.move:0 -msgid "You must assign a production lot for this product" -msgstr "Vous devez affecter un lot de fabrication pour ce produit." - -#. module: stock_move_location -#: selection:stock.inventory,type:0 -msgid "Location Move" -msgstr "Transfert de Stock à Stock" - -#. module: stock_move_location -#: view:stock.inventory:0 -msgid "Move Stock" -msgstr "Transfert de Stock à Stock" - -#. module: stock_move_location -#: model:ir.model,name:stock_move_location.model_stock_inventory -#: selection:stock.inventory,type:0 -msgid "Inventory" -msgstr "Inventaire" - -#. module: stock_move_location -#: code:addons/stock_move_location/stock.py:54 -#, python-format -msgid "Please inform the destination of your move" -msgstr "S'il vous plaît informer la destination de votre transfert" - -#. module: stock_move_location -#: code:addons/stock_move_location/stock.py:70 -#, python-format -msgid "is done." -msgstr "est fait." - -#. module: stock_move_location -#: field:stock.inventory,type:0 -msgid "Type" -msgstr "Type" - -#. module: stock_move_location -#: model:ir.module.module,shortdesc:stock_move_location.module_meta_information -msgid "Move Stock Location" -msgstr "Tranfert de stock à stock" - -#. module: stock_move_location -#: model:ir.actions.act_window,help:stock_move_location.action_move_stock_form -msgid "You can use this to move a stock from a location to an other one." -msgstr "Vous pouvez l'utiliser pour passer d'un stockage vers un autre." - -#. module: stock_move_location -#: field:stock.move,pack_history_id:0 -msgid "History pack" -msgstr "Historique du colis" - diff --git a/stock_move_location/i18n/stock_move_location.pot b/stock_move_location/i18n/stock_move_location.pot new file mode 100644 index 00000000000..80d94cf1118 --- /dev/null +++ b/stock_move_location/i18n/stock_move_location.pot @@ -0,0 +1,117 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_move_location +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-12-28 14:49+0000\n" +"PO-Revision-Date: 2018-12-28 14:49+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_move_location +#: model:ir.ui.view,arch_db:stock_move_location.view_stock_move_location_form_stock_move_location +msgid "Cancel" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_comments +msgid "Comments" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_create_uid +msgid "Created by" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_create_date +msgid "Created on" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_destination_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_line_destination_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_destination_location_id +msgid "Destination Location" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_display_name +msgid "Display Name" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_id_9042 +msgid "ID" +msgstr "" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_inventory +msgid "Inventory" +msgstr "" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_inventory_line +msgid "Inventory Line" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location___last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_move_location +#: model:ir.ui.view,arch_db:stock_move_location.view_stock_move_location_form_stock_move_location +msgid "Move Location" +msgstr "" + +#. module: stock_move_location +#: model:ir.actions.act_window,name:stock_move_location.stock_move_location_action +#: model:ir.ui.menu,name:stock_move_location.menuitem_move_location +msgid "Move from location..." +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_origin_location_id +msgid "Origin Location" +msgstr "" + +#. module: stock_move_location +#: code:addons/stock_move_location/models/stock_inventory.py:40 +#, python-format +msgid "Please select the destination of your move" +msgstr "" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_inventory_type +#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_line_inventory_type +msgid "Type" +msgstr "" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_stock_move_location +msgid "stock.move.location" +msgstr "" + diff --git a/stock_move_location/models/__init__.py b/stock_move_location/models/__init__.py new file mode 100644 index 00000000000..067b2103cba --- /dev/null +++ b/stock_move_location/models/__init__.py @@ -0,0 +1,6 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from . import stock_inventory +from . import inventory_line diff --git a/stock_move_location/models/inventory_line.py b/stock_move_location/models/inventory_line.py new file mode 100644 index 00000000000..cb41cad19e5 --- /dev/null +++ b/stock_move_location/models/inventory_line.py @@ -0,0 +1,47 @@ +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import fields, models + + +class InventoryLine(models.Model): + _inherit = "stock.inventory.line" + + destination_location_id = fields.Many2one( + related="inventory_id.destination_location_id", + readonly=True, + ) + inventory_type = fields.Selection( + related="inventory_id.inventory_type", + ) + + def _get_move_location_values(self): + self.ensure_one() + location_id = self.inventory_id.destination_location_id + date = self.inventory_id.date + return { + 'name': ("MOVE:{}:{}".format( + self.inventory_id.id, + self.inventory_id.name, + )), + 'move_line_ids': self._get_move_line_location_values(), + 'product_id': self.product_id.id, + 'product_uom': self.product_uom_id.id, + 'location_id': self.location_id.id, + 'location_dest_id': location_id.id, + 'date': date, + } + + def _get_move_line_location_values(self): + self.ensure_one() + location_id = self.inventory_id.destination_location_id + return [ + (0, 0, { + 'product_id': self.product_id.id, + 'lot_id': self.prod_lot_id.id, + 'location_id': self.location_id.id, + 'location_dest_id': location_id.id, + 'qty_done': self.product_qty, + 'product_uom_id': self.product_uom_id.id, + }) + ] diff --git a/stock_move_location/models/stock_inventory.py b/stock_move_location/models/stock_inventory.py new file mode 100644 index 00000000000..b2744f3e196 --- /dev/null +++ b/stock_move_location/models/stock_inventory.py @@ -0,0 +1,54 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from odoo import _, fields, models +from odoo.exceptions import ValidationError + + +_logger = logging.getLogger(__name__) + + +class StockInventory(models.Model): + _inherit = "stock.inventory" + + def _select_inventory_type(self): + return [ + ('normal', 'Inventory'), + ('move', 'Location Move'), + ] + + inventory_type = fields.Selection( + string='Type', + selection="_select_inventory_type", + default='normal', + ) + destination_location_id = fields.Many2one( + string='Destination Location', + comodel_name='stock.location', + ) + comments = fields.Text( + string='Comments', + ) + + def move_stock(self): + for inventory in self: + if not inventory.destination_location_id: + raise ValidationError( + _('Please select the destination of your move') + ) + moves = [ + (0, 0, line._get_move_location_values()) + for line in inventory.line_ids + ] + self.write({ + 'move_ids': moves, + }) + self.mapped('move_ids')._action_done() + self.write({ + "state": "done", + }) + _logger.info("Move '{}' is done.".format(inventory.name)) + return True diff --git a/stock_move_location/readme/CONTRIBUTORS.rst b/stock_move_location/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..012a547fecf --- /dev/null +++ b/stock_move_location/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Mathieu Vatel +* Mykhailo Panarin diff --git a/stock_move_location/readme/DESCRIPTION.rst b/stock_move_location/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..7b0eeb0eedb --- /dev/null +++ b/stock_move_location/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows to move entire location of products from one place to another diff --git a/stock_move_location/readme/USAGE.rst b/stock_move_location/readme/USAGE.rst new file mode 100644 index 00000000000..c047b1e2b6c --- /dev/null +++ b/stock_move_location/readme/USAGE.rst @@ -0,0 +1,9 @@ +* A new menuitem Stock > Move from location... opens a wizard + where 2 location ca be specified. +* Select origin and destination locations and press "MOVE LOCATION" +* Press `ADD ALL` button to add all products available +* Those lines can be edited. Move quantity can't be more than a max available quantity +* Move doesn't care about the reservations and will move stuff anyway +* If during you operation with the wizard the real quantity will change + it will move only the available quantity at the button press +* Products will be moved and a form view of inventory that did that will show up diff --git a/stock_move_location/stock.py b/stock_move_location/stock.py deleted file mode 100644 index be0a5ae2ef0..00000000000 --- a/stock_move_location/stock.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- -################################################################################# -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2011 Julius Network Solutions SARL -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -################################################################################# - -from osv import fields, osv -from tools.translate import _ - -#class stock_fill_inventory(osv.osv_memory): -# _inherit = "stock.fill.inventory" -# def fill_inventory(self, cr, uid, ids, context=None): -# res = super(stock_fill_inventory, self).fill_inventory(cr, uid, ids, context=context) -# stock_inventory_obj = self.pool.get('stock.inventory') -# fill_inventory = self.browse(cr, uid, ids[0], context=context) -# if stock_inventory_obj.browse(cr, uid, context.get('active_id', False), context).location_id: -# stock_inventory_obj.write(cr, uid, context.get('active_id', False), {'location_id': fill_inventory.location_id.id}) -# return res -#stock_fill_inventory() - -class stock_inventory(osv.osv): - _inherit = "stock.inventory" - - _columns = { - 'type': fields.selection([('normal', 'Inventory'),('move', 'Location Move')], 'Type'), - 'location_id': fields.many2one('stock.location', 'Location'), - 'location_dest_id': fields.many2one('stock.location', 'Destination Location'), - 'comments':fields.text('Comments'), - } - - def get_sequence(self, cr , uid, context): - if context.get('type', False) == 'move': - return self.pool.get('ir.sequence').get(cr, uid, 'stock.inventory.move') or '/' - else: - return self.pool.get('ir.sequence').get(cr, uid, 'stock.inventory') or '/' - - _defaults = { - 'type': lambda *a: 'normal', - 'name': lambda x, y, z, c: x.get_sequence(y,z,c), - } - - def move_stock(self, cr, uid, ids, context=None): - if context is None: - context = {} - product_context = dict(context, compute_child=False) - - location_obj = self.pool.get('stock.location') - for inv in self.browse(cr, uid, ids, context=context): - if not inv.location_dest_id: - raise osv.except_osv(_('Error !'), _('Please inform the destination of your move')) - move_ids = [] - for line in inv.inventory_line_id: - location_id = inv.location_dest_id.id - date = line.date or inv.date - value = { - 'name': 'MOVE:' + str(line.inventory_id.id) + ':' + line.inventory_id.name, - 'product_id': line.product_id.id, - 'product_uom': line.product_uom.id, - 'prodlot_id': line.prod_lot_id.id, - 'date': date, - 'product_qty': line.product_qty, - 'location_id': line.location_id.id, - 'location_dest_id': location_id, - 'note': line.note or inv.comments or False, - } - move_ids.append(self._inventory_line_hook(cr, uid, line, value)) - message = _('Move') + " '" + inv.name + "' "+ _("is done.") - self.log(cr, uid, inv.id, message) - self.write(cr, uid, [inv.id], {'state': 'confirm', 'move_ids': [(6, 0, move_ids)]}) - return True - - def fill_inventory(self, cr, uid, ids, context=False): - res = {} - stock_fill_inventory_obj = self.pool.get('stock.fill.inventory') - inventory_data = self.browse(cr, uid, ids[0], context) - if context.get('type',[]) == 'move': - set_stock_zero = False - else: - set_stock_zero = True - if inventory_data.location_id: - context['location_id'] = inventory_data.location_id.id - fill_inventory_id = stock_fill_inventory_obj.create(cr, uid, { - 'location_id': inventory_data.location_id.id, - 'set_stock_zero': set_stock_zero}) - context_temp = context - context_temp['active_ids'] = [inventory_data.id] - context_temp['active_id'] = inventory_data.id - stock_fill_inventory_obj.fill_inventory(cr, uid, [fill_inventory_id], context_temp) - - - if context.get('type',[]) == 'move': - act = {} -# mod_obj = self.pool.get('ir.model.data') -# act_obj = self.pool.get('ir.actions.act_window') -# model_id = mod_obj.search(cr, uid, [('name', '=', 'move_stock_acquisition_link_2')])[0] -# act_id = mod_obj.read(cr, uid, model_id, ['res_id'])['res_id'] -# act = act_obj.read(cr, uid, act_id) - else: - mod_obj = self.pool.get('ir.model.data') - act_obj = self.pool.get('ir.actions.act_window') - model_id = mod_obj.search(cr, uid, [('name', '=', 'inventory_acquisition_link_1')])[0] - act_id = mod_obj.read(cr, uid, model_id, ['res_id'])['res_id'] - act = act_obj.read(cr, uid, act_id) - context = eval(act['context']) - context['default_inventory_id'] = inventory_data.id - context['default_name'] = inventory_data.name - act['context'] = context - return act - - -stock_inventory() - -class stock_move(osv.osv): - - _inherit = 'stock.move' - -# def _check_move(self, cr, uid, ids, context=None): -# """ Checks if the given production lot belong to a pack -# Return false if the production lot is in a pack -# """ -# production_lot_obj = self.pool.get('stock.production.lot') -# -# for move in self.browse(cr, uid, ids, context=context): -# if move.prodlot_id: -# if self.search(cr, uid, [('prodlot_id', '=', move.prodlot_id.id), ('state','not in',('cancel','done')), ('id', '!=', move.id)]): -# if move.prodlot_id.tracking_id: -# return False -# return True - - _columns = { - 'pack_history_id': fields.many2one('stock.tracking.history', 'History pack'), - } - -# _constraints =[ -# (_check_move, 'You try to assign a move to a lot which is already in a pack', ['prodlot_id']) -# ] - ''' Solution to move all pack and production lot if one in a pack is move ''' -# def move_parent(self, cr, uid, ids, context=None): -# """ Checks if the given production lot belong to a pack -# Move the pack in the same destination -# """ -# ''' variables ''' -# production_lot_obj = self.pool.get('stock.production.lot') -# move_packaging_obj = self.pool.get('stock.move.packaging') -# ''' init ''' -# if context == None: -# context = {} -# ''' process ''' -# for move in self.browse(cr, uid, ids, context=context): -# if move.prodlot_id: -# if move.prodlot_id.tracking_id: -# move_packaging_obj.move_pack(cr, uid, move.prodlot_id.tracking_id, context) -# return {} - -stock_move() - -class stock_inventory_line(osv.osv): - _inherit = "stock.inventory.line" - - _columns = { - 'date': fields.datetime('Date'), - 'note': fields.text('Notes'), - } - -stock_inventory_line() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_move_location/stock_move_sequence.xml b/stock_move_location/stock_move_sequence.xml deleted file mode 100644 index 21d53d51a73..00000000000 --- a/stock_move_location/stock_move_sequence.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - Inventory Order - stock.inventory.move - - - - Inventory Order - stock.inventory.move - MOV - 3 - - - - diff --git a/stock_move_location/stock_view.xml b/stock_move_location/stock_view.xml deleted file mode 100755 index 89ad954f3ad..00000000000 --- a/stock_move_location/stock_view.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - stock.inventory.tree - stock.inventory - tree - - - - - - - - - - stock.inventory.form - stock.inventory - form - - - - - - - - - - - - - - {'full':'1', 'type':'normal', 'default_type': 'normal'} - [('type', '=', 'normal')] - - - - [('state','=','draft'), ('type', '=', 'normal')] - - - - Move stock - ir.actions.act_window - stock.inventory - form - - {'full':'1', 'type':'move', 'default_type': 'move'} - [('type', '=', 'move')] - - You can use this to move a stock from a location to an other one. - - - - - - diff --git a/stock_move_location/tests/__init__.py b/stock_move_location/tests/__init__.py new file mode 100644 index 00000000000..00527a8b077 --- /dev/null +++ b/stock_move_location/tests/__init__.py @@ -0,0 +1,6 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from . import test_common +from . import test_move_location diff --git a/stock_move_location/tests/test_common.py b/stock_move_location/tests/test_common.py new file mode 100644 index 00000000000..a002da97035 --- /dev/null +++ b/stock_move_location/tests/test_common.py @@ -0,0 +1,68 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.tests import common + + +class TestsCommon(common.SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestsCommon, cls).setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.location_obj = cls.env["stock.location"] + product_obj = cls.env["product.product"] + cls.wizard_obj = cls.env["wiz.stock.move.location"] + cls.quant_obj = cls.env["stock.quant"] + + cls.internal_loc_1 = cls.location_obj.create({ + "name": "INT_1", + "usage": "internal", + "active": True, + }) + cls.internal_loc_2 = cls.location_obj.create({ + "name": "INT_2", + "usage": "internal", + "active": True, + }) + cls.uom_unit = cls.env.ref('product.product_uom_unit') + cls.product_no_lots = product_obj.create({ + "name": "Pineapple", + "type": "product", + "tracking": "none", + 'categ_id': cls.env.ref('product.product_category_all').id, + }) + cls.product_lots = product_obj.create({ + "name": "Pineapple", + "type": "product", + "tracking": "lot", + 'categ_id': cls.env.ref('product.product_category_all').id, + }) + cls.lot1 = cls.env['stock.production.lot'].create({ + 'product_id': cls.product_lots.id, + }) + cls.lot2 = cls.env['stock.production.lot'].create({ + 'product_id': cls.product_lots.id, + }) + cls.lot3 = cls.env['stock.production.lot'].create({ + 'product_id': cls.product_lots.id, + }) + + def set_product_amount(self, product, location, amount, lot_id=None): + self.env['stock.quant']._update_available_quantity( + product, + location, + amount, + lot_id=lot_id, + ) + + def check_product_amount(self, product, location, amount, lot_id=None): + self.assertEqual( + self.env['stock.quant']._get_available_quantity( + product, + location, + lot_id=lot_id, + ), + amount, + ) diff --git a/stock_move_location/tests/test_move_location.py b/stock_move_location/tests/test_move_location.py new file mode 100644 index 00000000000..e9a2b4cd1b3 --- /dev/null +++ b/stock_move_location/tests/test_move_location.py @@ -0,0 +1,154 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from .test_common import TestsCommon +from odoo.exceptions import ValidationError + + +class TestMoveLocation(TestsCommon): + + def test_move_location_wizard(self): + """Test a simple move. + """ + self.set_product_amount( + self.product_no_lots, + self.internal_loc_1, + 123, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot1, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot2, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot3, + ) + + wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) + wizard.add_lines() + wizard.action_move_location() + self.check_product_amount( + self.product_no_lots, self.internal_loc_1, 0, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_1, 0, self.lot1, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_1, 0, self.lot1, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_1, 0, self.lot1, + ) + self.check_product_amount( + self.product_no_lots, self.internal_loc_2, 123, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_2, 1, self.lot1, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_2, 1, self.lot1, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_2, 1, self.lot1, + ) + + def _create_wizard(self, origin_location, destination_location): + return self.wizard_obj.create({ + "origin_location_id": origin_location.id, + "destination_location_id": destination_location.id, + }) + + def test_move_location_wizard_amount(self): + """Can't move more than exists + """ + self.set_product_amount( + self.product_no_lots, + self.internal_loc_1, + 123, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot1, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot2, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot3, + ) + + wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) + wizard.add_lines() + with self.assertRaises(ValidationError): + wizard.stock_move_location_line_ids[0].move_quantity += 1 + + def test_move_location_wizard_ignore_reserved(self): + """Can't move more than exists + """ + self.set_product_amount( + self.product_no_lots, + self.internal_loc_1, + 123, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot1, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot2, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot3, + ) + wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) + wizard.add_lines() + # reserve some quants + self.quant_obj._update_reserved_quantity( + self.product_no_lots, + self.internal_loc_1, + 50, + ) + self.quant_obj._update_reserved_quantity( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot1, + ) + # doesn't care about reservations, everything is moved + wizard.action_move_location() + self.check_product_amount( + self.product_no_lots, self.internal_loc_1, 0, + ) + self.check_product_amount( + self.product_no_lots, self.internal_loc_2, 123, + ) + self.check_product_amount( + self.product_lots, self.internal_loc_2, 1, self.lot1, + ) diff --git a/stock_move_location/views/stock_view.xml b/stock_move_location/views/stock_view.xml new file mode 100755 index 00000000000..4bffb96b70e --- /dev/null +++ b/stock_move_location/views/stock_view.xml @@ -0,0 +1,20 @@ + + + + + stock.inventory.form.stock_move_location + stock.inventory + + + + + + + + + + + + + + diff --git a/stock_move_location/wizard/__init__.py b/stock_move_location/wizard/__init__.py index 4096c452a3f..d9fdbf21cac 100644 --- a/stock_move_location/wizard/__init__.py +++ b/stock_move_location/wizard/__init__.py @@ -1,24 +1,6 @@ -# -*- coding: utf-8 -*- -################################################################################# -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2011 Julius Network Solutions SARL -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -################################################################################# +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -import move_location - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +from . import stock_move_location +from . import stock_move_location_line diff --git a/stock_move_location/wizard/move_location.py b/stock_move_location/wizard/move_location.py deleted file mode 100644 index a27155d2a03..00000000000 --- a/stock_move_location/wizard/move_location.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -################################################################################# -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2011 Julius Network Solutions SARL -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -################################################################################# - -from osv import fields, osv -from tools.translate import _ - -class stock_fill_inventory(osv.osv_memory): - _inherit = "stock.fill.inventory" - - def _get_location(self, cr, uid, active_id, context={}): - res = False - if active_id: - inv = self.pool.get('stock.inventory').browse(cr, uid, active_id) - if inv.location_id: - res = inv.location_id.id - return res - - _columns = { - 'location_id': fields.many2one('stock.location', 'Location', required=True), - } - - _defaults = { - 'location_id': lambda s,cr,uid,c: s._get_location(cr, uid, c.get('active_id',False), c), - } - -stock_fill_inventory() - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_move_location/wizard/move_location_view.xml b/stock_move_location/wizard/move_location_view.xml deleted file mode 100755 index 88c70a085b2..00000000000 --- a/stock_move_location/wizard/move_location_view.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - diff --git a/stock_move_location/wizard/stock_move_location.py b/stock_move_location/wizard/stock_move_location.py new file mode 100644 index 00000000000..343a870ecd9 --- /dev/null +++ b/stock_move_location/wizard/stock_move_location.py @@ -0,0 +1,185 @@ +# Copyright (C) 2011 Julius Network Solutions SARL +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class StockMoveLocationWizard(models.TransientModel): + _name = "wiz.stock.move.location" + + origin_location_id = fields.Many2one( + string='Origin Location', + comodel_name='stock.location', + required=True, + domain=lambda self: self._get_locations_domain(), + ) + destination_location_id = fields.Many2one( + string='Destination Location', + comodel_name='stock.location', + required=True, + domain=lambda self: self._get_locations_domain(), + ) + stock_move_location_line_ids = fields.One2many( + string="Move Location lines", + comodel_name="wiz.stock.move.location.line", + inverse_name="move_location_wizard_id", + ) + + @api.onchange('origin_location_id', 'destination_location_id') + def _onchange_locations(self): + self._clear_lines() + + def _clear_lines(self): + origin = self.origin_location_id + destination = self.destination_location_id + # there is `invalidate_cache` call inside the unlink + # which will clear the wizard - not cool. + # we have to keep the values somehow + self.stock_move_location_line_ids.unlink() + self.origin_location_id = origin + self.destination_location_id = destination + + def _get_locations_domain(self): + return [('usage', '=', 'internal')] + + def action_move_location(self): + inventory_obj = self.env["stock.inventory"] + collected_inventory = inventory_obj.create( + self._get_collected_inventory_values() + ) + collected_inventory.action_start() + self.set_inventory_lines(collected_inventory) + collected_inventory.move_stock() + return self._get_inventory_action(collected_inventory.id) + + def _get_collected_inventory_name(self): + sequence = self.env['ir.sequence'].next_by_code( + 'stock.inventory.move') or '/' + res = "{sequence}:{location_from}:{location_to}".format( + sequence=sequence, + location_from=self.origin_location_id.display_name, + location_to=self.destination_location_id.display_name, + ) + return res + + def _get_collected_inventory_values(self): + return { + "name": self._get_collected_inventory_name(), + "location_id": self.origin_location_id.id, + "inventory_type": "move", + "destination_location_id": self.destination_location_id.id, + "filter": "partial", + } + + def _get_inventory_action(self, inventory_id): + action = self.env.ref("stock.action_inventory_form").read()[0] + form_view = self.env.ref("stock.view_inventory_form").id + action.update({ + "view_mode": "form", + "views": [(form_view, "form")], + "res_id": inventory_id, + }) + return action + + def _get_group_quants_sql(self): + location_id = self.origin_location_id.id + company = self.env['res.company']._company_default_get( + 'stock.inventory', + ) + return """ + SELECT product_id, lot_id, SUM(quantity) + FROM stock_quant + WHERE location_id = {location_id} AND company_id = {company_id} + GROUP BY product_id, lot_id + """.format( + location_id=location_id, + company_id=company.id, + ) + + def _get_stock_move_location_lines_values(self): + product_obj = self.env['product.product'] + + # Using sql as search_group doesn't support aggregation functions + # leading to overhead in queries to DB + self.env.cr.execute(self._get_group_quants_sql()) + product_data = [] + for group in self.env.cr.dictfetchall(): + product = product_obj.browse(group.get("product_id")).exists() + product_data.append({ + 'product_id': product.id, + 'move_quantity': group.get("sum"), + 'max_quantity': group.get("sum"), + 'origin_location_id': self.origin_location_id.id, + 'destination_location_id': self.destination_location_id.id, + # cursor returns None instead of False + 'lot_id': group.get("lot_id") or False, + 'product_uom_id': product.uom_id.id, + 'move_location_wizard_id': self.id, + }) + return product_data + + def add_lines(self): + self.ensure_one() + if not self.stock_move_location_line_ids: + for line_val in self._get_stock_move_location_lines_values(): + self.env["wiz.stock.move.location.line"].create(line_val).id + return { + "type": "ir.actions.do_nothing", + } + + def clear_lines(self): + self._clear_lines() + return { + "type": "ir.action.do_nothing", + } + + def _get_inventory_lines_values(self, inventory): + self.ensure_one() + lines = [] + for wizard_line in self.stock_move_location_line_ids: + lines.append({ + 'product_id': wizard_line.product_id.id, + 'product_uom_id': wizard_line.product_uom_id.id, + 'prod_lot_id': wizard_line.lot_id.id, + 'product_qty': self._get_available_quantity(wizard_line), + 'inventory_id': inventory.id, + 'location_id': self.origin_location_id.id, + }) + return lines + + def set_inventory_lines(self, inventory): + inventory_line_obj = self.env["stock.inventory.line"] + for line_vals in self._get_inventory_lines_values(inventory): + inventory_line_obj.create(line_vals) + + def _get_available_quantity(self, line): + """We check here if the actual amount changed in the stock. + + We don't care about the reservations but we do care about not moving + more than exists.""" + if not line.product_id: + return 0 + # switched to sql here to improve performance and lower db queries + self.env.cr.execute(self._get_specific_quants_sql(line)) + available_qty = self.env.cr.fetchone()[0] + if available_qty < line.move_quantity: + return available_qty + return line.move_quantity + + def _get_specific_quants_sql(self, line): + lot = "AND lot_id = {}".format(line.lot_id.id) + if not line.lot_id: + lot = "AND lot_id is null" + return """ + SELECT sum(quantity) + FROM stock_quant + WHERE location_id = {location} + {lot} + AND product_id = {product} + GROUP BY location_id, product_id, lot_id + """.format( + location=line.origin_location_id.id, + product=line.product_id.id, + lot=lot, + ) diff --git a/stock_move_location/wizard/stock_move_location.xml b/stock_move_location/wizard/stock_move_location.xml new file mode 100755 index 00000000000..e3d6587a799 --- /dev/null +++ b/stock_move_location/wizard/stock_move_location.xml @@ -0,0 +1,54 @@ + + + + + wiz.stock.move.location.form.stock_move_location + wiz.stock.move.location + +
+ + + + + + +