From e2aa9b603ff2272d22a7e907b4dba36b6cc5049f Mon Sep 17 00:00:00 2001 From: Mathieu Vatel Date: Wed, 7 Mar 2012 13:56:37 +0100 Subject: [PATCH] Extra modules Julius V1.0 --- stock_inventory_existing_lines/__init__.py | 24 + stock_inventory_existing_lines/__openerp__.py | 43 ++ stock_inventory_existing_lines/i18n/fr.po | 100 +++ .../security/ir.model.access.csv | 3 + stock_inventory_existing_lines/stock.py | 92 +++ stock_inventory_existing_lines/stock_view.xml | 51 ++ stock_inventory_extended/__init__.py | 25 + stock_inventory_extended/__openerp__.py | 43 ++ stock_inventory_extended/i18n/fr.po | 86 +++ stock_inventory_extended/stock.py | 96 +++ stock_inventory_extended/stock_view.xml | 29 + stock_inventory_extended/wizard/__init__.py | 27 + .../wizard/stock_fill_inventory.py | 132 ++++ .../wizard/stock_fill_inventory_view.xml | 48 ++ stock_inventory_with_location/__init__.py | 24 + stock_inventory_with_location/__openerp__.py | 40 ++ stock_inventory_with_location/stock.py | 60 ++ stock_move_location/__init__.py | 25 + stock_move_location/__openerp__.py | 44 ++ stock_move_location/i18n/fr.po | 143 +++++ stock_move_location/stock.py | 181 ++++++ 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 + stock_move_on_hold/__init__.py | 26 + stock_move_on_hold/__openerp__.py | 46 ++ stock_move_on_hold/invoice.py | 57 ++ stock_move_on_hold/product.py | 60 ++ stock_move_on_hold/stock.py | 582 ++++++++++++++++++ stock_move_on_hold/stock_view.xml | 139 +++++ stock_move_on_hold/stock_workflow.xml | 103 ++++ .../wizard/stock_invoice_onshipping_view.xml | 35 ++ stock_move_packaging/__init__.py | 25 + stock_move_packaging/__openerp__.py | 43 ++ stock_move_packaging/i18n/fr.po | 97 +++ stock_move_packaging/stock.py | 45 ++ stock_move_packaging/stock_view.xml | 31 + stock_move_packaging/wizard/__init__.py | 24 + stock_move_packaging/wizard/move_pack.py | 104 ++++ .../wizard/move_pack_view.xml | 47 ++ stock_tracking_add_move/__init__.py | 25 + stock_tracking_add_move/__openerp__.py | 45 ++ stock_tracking_add_move/i18n/fr.po | 145 +++++ .../security/ir.model.access.csv | 3 + stock_tracking_add_move/stock.py | 203 ++++++ stock_tracking_add_move/stock_view.xml | 63 ++ stock_tracking_add_move/wizard/__init__.py | 24 + stock_tracking_add_move/wizard/add_move.py | 74 +++ .../wizard/add_move_view.xml | 82 +++ stock_tracking_extended/__init__.py | 24 + stock_tracking_extended/__openerp__.py | 43 ++ stock_tracking_extended/i18n/fr.po | 279 +++++++++ .../inventory_sequence.xml | 19 + .../security/ir.model.access.csv | 10 + stock_tracking_extended/stock_tracking.py | 316 ++++++++++ .../stock_tracking_view.xml | 270 ++++++++ stock_tracking_reopen/__init__.py | 24 + stock_tracking_reopen/__openerp__.py | 43 ++ stock_tracking_reopen/i18n/fr.po | 57 ++ stock_tracking_reopen/stock.py | 133 ++++ stock_tracking_reopen/stock_view.xml | 30 + 63 files changed, 4882 insertions(+) create mode 100644 stock_inventory_existing_lines/__init__.py create mode 100644 stock_inventory_existing_lines/__openerp__.py create mode 100644 stock_inventory_existing_lines/i18n/fr.po create mode 100644 stock_inventory_existing_lines/security/ir.model.access.csv create mode 100644 stock_inventory_existing_lines/stock.py create mode 100755 stock_inventory_existing_lines/stock_view.xml create mode 100644 stock_inventory_extended/__init__.py create mode 100644 stock_inventory_extended/__openerp__.py create mode 100644 stock_inventory_extended/i18n/fr.po create mode 100644 stock_inventory_extended/stock.py create mode 100755 stock_inventory_extended/stock_view.xml create mode 100644 stock_inventory_extended/wizard/__init__.py create mode 100644 stock_inventory_extended/wizard/stock_fill_inventory.py create mode 100644 stock_inventory_extended/wizard/stock_fill_inventory_view.xml create mode 100644 stock_inventory_with_location/__init__.py create mode 100644 stock_inventory_with_location/__openerp__.py create mode 100644 stock_inventory_with_location/stock.py 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 create mode 100644 stock_move_on_hold/__init__.py create mode 100644 stock_move_on_hold/__openerp__.py create mode 100644 stock_move_on_hold/invoice.py create mode 100644 stock_move_on_hold/product.py create mode 100644 stock_move_on_hold/stock.py create mode 100644 stock_move_on_hold/stock_view.xml create mode 100644 stock_move_on_hold/stock_workflow.xml create mode 100644 stock_move_on_hold/wizard/stock_invoice_onshipping_view.xml create mode 100644 stock_move_packaging/__init__.py create mode 100644 stock_move_packaging/__openerp__.py create mode 100644 stock_move_packaging/i18n/fr.po create mode 100644 stock_move_packaging/stock.py create mode 100755 stock_move_packaging/stock_view.xml create mode 100644 stock_move_packaging/wizard/__init__.py create mode 100644 stock_move_packaging/wizard/move_pack.py create mode 100755 stock_move_packaging/wizard/move_pack_view.xml create mode 100644 stock_tracking_add_move/__init__.py create mode 100644 stock_tracking_add_move/__openerp__.py create mode 100644 stock_tracking_add_move/i18n/fr.po create mode 100644 stock_tracking_add_move/security/ir.model.access.csv create mode 100644 stock_tracking_add_move/stock.py create mode 100644 stock_tracking_add_move/stock_view.xml create mode 100644 stock_tracking_add_move/wizard/__init__.py create mode 100644 stock_tracking_add_move/wizard/add_move.py create mode 100755 stock_tracking_add_move/wizard/add_move_view.xml create mode 100644 stock_tracking_extended/__init__.py create mode 100644 stock_tracking_extended/__openerp__.py create mode 100644 stock_tracking_extended/i18n/fr.po create mode 100644 stock_tracking_extended/inventory_sequence.xml create mode 100644 stock_tracking_extended/security/ir.model.access.csv create mode 100644 stock_tracking_extended/stock_tracking.py create mode 100644 stock_tracking_extended/stock_tracking_view.xml create mode 100644 stock_tracking_reopen/__init__.py create mode 100644 stock_tracking_reopen/__openerp__.py create mode 100644 stock_tracking_reopen/i18n/fr.po create mode 100644 stock_tracking_reopen/stock.py create mode 100644 stock_tracking_reopen/stock_view.xml diff --git a/stock_inventory_existing_lines/__init__.py b/stock_inventory_existing_lines/__init__.py new file mode 100644 index 000000000..50d10b8de --- /dev/null +++ b/stock_inventory_existing_lines/__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 stock + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_inventory_existing_lines/__openerp__.py b/stock_inventory_existing_lines/__openerp__.py new file mode 100644 index 000000000..0b0b73d3e --- /dev/null +++ b/stock_inventory_existing_lines/__openerp__.py @@ -0,0 +1,43 @@ +# -*- 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" : "Invetory Extended", + "version" : "1.0", + "author" : "Julius Network Solutions", + "description" : """ This module adds a new field based on lines into the inventory + to know what are lines correctly in the system """, + "website" : "http://www.julius.fr", + "depends" : [ + "stock", + ], + "category" : "Customs/Stock", + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + 'stock_view.xml', + "security/ir.model.access.csv", + ], + 'test': [], + 'installable': True, + 'active': False, + 'certificate': '', +} diff --git a/stock_inventory_existing_lines/i18n/fr.po b/stock_inventory_existing_lines/i18n/fr.po new file mode 100644 index 000000000..d508f67c6 --- /dev/null +++ b/stock_inventory_existing_lines/i18n/fr.po @@ -0,0 +1,100 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * stock_inventory_existing_lines +# +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:50+0000\n" +"PO-Revision-Date: 2011-12-19 10:50+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_inventory_existing_lines +#: view:stock.inventory:0 +msgid "General Informations" +msgstr "Informations générales" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,product_id:0 +msgid "Product" +msgstr "Produit" + +#. module: stock_inventory_existing_lines +#: model:ir.model,name:stock_inventory_existing_lines.model_stock_inventory_line2 +msgid "stock.inventory.line2" +msgstr "stock.inventory.line2" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,state:0 +msgid "State" +msgstr "Etat" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,company_id:0 +msgid "Company" +msgstr "Société" + +#. module: stock_inventory_existing_lines +#: view:stock.inventory:0 +msgid "Lines" +msgstr "Lignes correspondantes" + +#. module: stock_inventory_existing_lines +#: model:ir.module.module,description:stock_inventory_existing_lines.module_meta_information +msgid " This module adds a new field based on lines into the inventory\n" +" to know what are lines correctly in the system " +msgstr " Ce module ajoute un nouveau champ basé sur des lignes dans l'inventaire\n" +" pour savoir quelles sont les lignes qui existent déjà dans le système " + +#. module: stock_inventory_existing_lines +#: view:stock.inventory.line2:0 +msgid "Stock Inventory Lines" +msgstr "Lignes d'inventaires des stocks" + +#. module: stock_inventory_existing_lines +#: model:ir.module.module,shortdesc:stock_inventory_existing_lines.module_meta_information +msgid "Invetory Extended" +msgstr "Inventaire étendu" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,product_qty:0 +msgid "Quantity" +msgstr "Quantité" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,product_uom:0 +msgid "Product UOM" +msgstr "Produit UdM" + +#. module: stock_inventory_existing_lines +#: model:ir.model,name:stock_inventory_existing_lines.model_stock_inventory +#: field:stock.inventory.line2,inventory_id:0 +msgid "Inventory" +msgstr "Inventaire" + +#. module: stock_inventory_existing_lines +#: view:stock.inventory:0 +msgid "Correct lines" +msgstr "Lignes correspondantes" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory,inventory_line_id2:0 +msgid "Inventories" +msgstr "Inventaires" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,prod_lot_id:0 +msgid "Production Lot" +msgstr "Numéro de série" + +#. module: stock_inventory_existing_lines +#: field:stock.inventory.line2,location_id:0 +msgid "Location" +msgstr "Emplacement" + diff --git a/stock_inventory_existing_lines/security/ir.model.access.csv b/stock_inventory_existing_lines/security/ir.model.access.csv new file mode 100644 index 000000000..fb1953e81 --- /dev/null +++ b/stock_inventory_existing_lines/security/ir.model.access.csv @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_stock_inventory_line2_user","stock.inventory.line2 user","model_stock_inventory_line2","stock.group_stock_user",1,1,1,1 +"access_stock_inventory_line2_manager","stock.inventory.line2 manager","model_stock_inventory_line2","stock.group_stock_manager",1,1,1,1 diff --git a/stock_inventory_existing_lines/stock.py b/stock_inventory_existing_lines/stock.py new file mode 100644 index 000000000..7faa1a203 --- /dev/null +++ b/stock_inventory_existing_lines/stock.py @@ -0,0 +1,92 @@ +# -*- 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 _ + +import decimal_precision as dp + +class stock_inventory(osv.osv): + _inherit = "stock.inventory" + + _columns = { + 'inventory_line_id2': fields.one2many('stock.inventory.line2', 'inventory_id', 'Inventories', states={'done': [('readonly', True)]}), + } + + def action_confirm(self, cr, uid, ids, context=None): + if context is None: + context = {} + ''' to perform the correct inventory corrections we need analyze stock location by + location, never recursively, so we use a special context ''' + product_context = dict(context, compute_child=False) + + location_obj = self.pool.get('stock.location') + line_obj = self.pool.get('stock.inventory.line') + line2_obj = self.pool.get('stock.inventory.line2') + for inv in self.browse(cr, uid, ids, context=context): + move_ids = [] + for line in inv.inventory_line_id: +# ''' if the production lot is tracked but do not have a serial code then it is not taken into account ''' +# if line.product_id.categ_id.tracked and not line.prod_lot_id: +# continue + if not line.product_qty: + continue + pid = line.product_id.id + date = line.date or inv.date + product_context.update(uom=line.product_uom.id, date=date, to_date=date, prodlot_id=line.prod_lot_id.id) + amount = location_obj._product_get(cr, uid, line.location_id.id, [pid], product_context)[pid] + if not amount: + continue + val_qty = min(line.product_qty,amount) + if val_qty and val_qty > 0: + vals = line_obj.copy_data(cr, uid, line.id) + line2_obj.create(cr, uid, vals) +# location_id = line.product_id.product_tmpl_id.property_stock_inventory.id + res = super(stock_inventory, self).action_confirm(cr, uid, ids, context) + return res + +stock_inventory() + +#class stock_move(osv.osv): +# _inherit = "stock.move" +# +# _columns = { +# 'inventory_type': fields.selection([('in','In'),('out','Out')], 'Inventory type') +# } +#stock_move() + +class stock_inventory_line2(osv.osv): + _name = "stock.inventory.line2" + + _columns = { + 'inventory_id': fields.many2one('stock.inventory', 'Inventory', ondelete='cascade', select=True), + 'location_id': fields.many2one('stock.location', 'Location', required=True), + 'product_id': fields.many2one('product.product', 'Product', required=True, select=True), + 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True), + 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product UoM')), + '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', 'Production Lot', domain="[('product_id','=',product_id)]"), + 'state': fields.related('inventory_id', 'state', type='char', string='State',readonly=True), + } + +stock_inventory_line2() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_inventory_existing_lines/stock_view.xml b/stock_inventory_existing_lines/stock_view.xml new file mode 100755 index 000000000..63da7c1ed --- /dev/null +++ b/stock_inventory_existing_lines/stock_view.xml @@ -0,0 +1,51 @@ + + + + + + stock.inventory.line2.tree + stock.inventory.line2 + tree + + + + + + + + + + + + stock.inventory.line2.form + stock.inventory.line2 + form + +
+ + + + + + + +
+ + + stock.inventory.form + stock.inventory + form + + + + + + + + + + + + +
+
diff --git a/stock_inventory_extended/__init__.py b/stock_inventory_extended/__init__.py new file mode 100644 index 000000000..c2c2ebef6 --- /dev/null +++ b/stock_inventory_extended/__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_inventory_extended/__openerp__.py b/stock_inventory_extended/__openerp__.py new file mode 100644 index 000000000..79b4e2bf6 --- /dev/null +++ b/stock_inventory_extended/__openerp__.py @@ -0,0 +1,43 @@ +# -*- 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 Invetory Extended", + "version" : "1.0", + "author" : "Julius Network Solutions", + "description" : """ This module adds a new field based on lines into the inventory + to get all lines pre-filled and all lines scanned """, + "website" : "http://www.julius.fr", + "depends" : [ + "stock", + ], + "category" : "Customs/Stock", + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + 'stock_view.xml', +# 'wizard/stock_fill_inventory_view.xml', + ], + 'test': [], + 'installable': True, + 'active': False, + 'certificate': '', +} diff --git a/stock_inventory_extended/i18n/fr.po b/stock_inventory_extended/i18n/fr.po new file mode 100644 index 000000000..3c24b35bc --- /dev/null +++ b/stock_inventory_extended/i18n/fr.po @@ -0,0 +1,86 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * stock_inventory_extended +# +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:54+0000\n" +"PO-Revision-Date: 2011-12-19 10:54+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_inventory_extended +#: code:addons/stock_inventory_extended/wizard/stock_fill_inventory.py:47 +#, python-format +msgid "You cannot perform this operation on more than one Stock Inventories." +msgstr "Vous ne pouvez pas effectuer cette opération sur plusieurs inventaires de stock." + +#. module: stock_inventory_extended +#: model:ir.model,name:stock_inventory_extended.model_stock_fill_inventory +msgid "Import Inventory" +msgstr "Importer un inventaire" + +#. module: stock_inventory_extended +#: model:ir.model,name:stock_inventory_extended.model_stock_inventory_line +msgid "Inventory Line" +msgstr "Lignes d'inventaire" + +#. module: stock_inventory_extended +#: field:stock.inventory.line,note:0 +msgid "Notes" +msgstr "Notes" + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/wizard/stock_fill_inventory.py:47 +#, python-format +msgid "Error!" +msgstr "Erreur!" + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/wizard/stock_fill_inventory.py:111 +#, python-format +msgid "No product in this location." +msgstr "Aucun produit à cet endroit." + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/wizard/stock_fill_inventory.py:53 +#, python-format +msgid "Stock Inventory is already Validated." +msgstr "L'inventaire est déjà validé." + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/stock.py:77 +#: model:ir.model,name:stock_inventory_extended.model_stock_inventory +#, python-format +msgid "Inventory" +msgstr "Inventaire" + +#. module: stock_inventory_extended +#: field:stock.inventory.line,date:0 +msgid "Date" +msgstr "Date" + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/wizard/stock_fill_inventory.py:111 +#, python-format +msgid "Warning !" +msgstr "Attention !" + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/stock.py:77 +#, python-format +msgid "is done." +msgstr "est fait." + +#. module: stock_inventory_extended +#: code:addons/stock_inventory_extended/wizard/stock_fill_inventory.py:53 +#, python-format +msgid "Warning!" +msgstr "Attention!" + diff --git a/stock_inventory_extended/stock.py b/stock_inventory_extended/stock.py new file mode 100644 index 000000000..7e2f78293 --- /dev/null +++ b/stock_inventory_extended/stock.py @@ -0,0 +1,96 @@ +# -*- 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_inventory(osv.osv): + _inherit = "stock.inventory" + + _columns = { + 'comments':fields.text('Comments'), + } + + def action_confirm(self, cr, uid, ids, context=None): + """ Confirm the inventory and writes its finished date + @return: True + """ + res = super(stock_inventory, self).action_confirm(cr, uid, ids, context) + + if context is None: + context = {} + # to perform the correct inventory corrections we need analyze stock location by + # location, never recursively, so we use a special 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): + move_ids = [] + self.write(cr, uid, [inv.id], {'move_ids': [(6, 0, move_ids)]}) + for line in inv.inventory_line_id: + pid = line.product_id.id + date = line.date or inv.date + product_context.update(uom=line.product_uom.id, date=date, to_date=date, prodlot_id=line.prod_lot_id.id) + amount = location_obj._product_get(cr, uid, line.location_id.id, [pid], product_context)[pid] + + change = line.product_qty - amount + lot_id = line.prod_lot_id.id + if change: + location_id = line.product_id.product_tmpl_id.property_stock_inventory.id + value = { + 'name': 'INV:' + str(line.inventory_id.id) + ':' + line.inventory_id.name, + 'product_id': line.product_id.id, + 'product_uom': line.product_uom.id, + 'prodlot_id': lot_id, + 'date': date, + 'note': line.note or inv.comments or False, + } + if change > 0: + value.update( { + 'product_qty': change, + 'location_id': location_id, + 'location_dest_id': line.location_id.id, + }) + else: + value.update( { + 'product_qty': -change, + 'location_id': line.location_id.id, + 'location_dest_id': location_id, + }) + move_ids.append(self._inventory_line_hook(cr, uid, line, value)) + message = _('Inventory') + " '" + 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 res + +stock_inventory() + +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: \ No newline at end of file diff --git a/stock_inventory_extended/stock_view.xml b/stock_inventory_extended/stock_view.xml new file mode 100755 index 000000000..57dd7b984 --- /dev/null +++ b/stock_inventory_extended/stock_view.xml @@ -0,0 +1,29 @@ + + + + + + stock.inventory.form + stock.inventory + form + + 16 + + + + + + + + + + + + + + + + + + + diff --git a/stock_inventory_extended/wizard/__init__.py b/stock_inventory_extended/wizard/__init__.py new file mode 100644 index 000000000..98caa9231 --- /dev/null +++ b/stock_inventory_extended/wizard/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +import stock_fill_inventory +#import stock_inventory_line_split + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/stock_inventory_extended/wizard/stock_fill_inventory.py b/stock_inventory_extended/wizard/stock_fill_inventory.py new file mode 100644 index 000000000..0e143de5e --- /dev/null +++ b/stock_inventory_extended/wizard/stock_fill_inventory.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero 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" +# _description = "Import Inventory" +# _columns = { +# 'location_id': fields.many2one('stock.location', 'Location', required=True), +# 'recursive': fields.boolean("Include children",help="If checked, products contained in child locations of selected location will be included as well."), +# 'set_stock_zero': fields.boolean("Set to zero",help="If checked, all product quantities will be set to zero to help ensure a real physical inventory is done"), +# } +# def view_init(self, cr, uid, fields_list, context=None): +# """ +# Creates view dynamically and adding fields at runtime. +# @param self: The object pointer. +# @param cr: A database cursor +# @param uid: ID of the user currently logged in +# @param context: A standard dictionary +# @return: New arch of view with new columns. +# """ +# if context is None: +# context = {} +# super(stock_fill_inventory2, self).view_init(cr, uid, fields_list, context=context) +# +# if len(context.get('active_ids',[])) > 1: +# raise osv.except_osv(_('Error!'), _('You cannot perform this operation on more than one Stock Inventories.')) +# +# if context.get('active_id', False): +# stock = self.pool.get('stock.inventory').browse(cr, uid, context.get('active_id', False)) +# +# if stock.state == 'done': +# raise osv.except_osv(_('Warning!'), _('Stock Inventory is already Validated.')) +# return True + + def fill_inventory(self, cr, uid, ids, context=None): + """ To Import stock inventory according to products available in the selected locations. + @param self: The object pointer. + @param cr: A database cursor + @param uid: ID of the user currently logged in + @param ids: the ID or list of IDs if we want more than one + @param context: A standard dictionary + @return: + """ + if context is None: + context = {} + + inventory_line_obj = self.pool.get('stock.inventory.line') + location_obj = self.pool.get('stock.location') + product_obj = self.pool.get('product.product') + move_obj = self.pool.get('stock.move') + + fill_inventory = self.browse(cr, uid, ids[0], context=context) + res = {} + res_location = {} + + if fill_inventory.recursive: + location_ids = location_obj.search(cr, uid, [('location_id', + 'child_of', [fill_inventory.location_id.id])],context=context) + else: + location_ids = [fill_inventory.location_id.id] + + res = {} + flag = False + + for location in location_ids: + datas = {} + res[location] = {} + domain = [('location_dest_id','=',location),('state','=','done')] + active_ids = context.get('active_ids', False) + if active_ids: + date = self.pool.get('stock.inventory').browse(cr, uid, active_ids[0]).date + domain.append(('date','<=',date)) + move_ids = move_obj.search(cr, uid, domain, context=context) + + for move in move_obj.browse(cr, uid, move_ids, context=context): + lot_id = move.prodlot_id.id + prod_id = move.product_id.id + qty = move.product_qty + + if datas.get((prod_id, lot_id)): + qty += datas[(prod_id, lot_id)]['product_qty'] + + datas[(prod_id, lot_id)] = {'product_id': prod_id, 'location_id': location, 'product_qty': qty, 'product_uom': move.product_id.uom_id.id, 'prod_lot_id': lot_id} + + if datas: + flag = True + res[location] = datas + + if not flag: + raise osv.except_osv(_('Warning !'), _('No product in this location.')) + + for stock_move in res.values(): + for stock_move_details in stock_move.values(): + stock_move_details.update({'inventory_id': context['active_ids'][0]}) + domain = [] + + if fill_inventory.set_stock_zero: + stock_move_details.update({'product_qty': 0}) + + for field, value in stock_move_details.items(): + domain.append((field, '=', value)) + line_ids = inventory_line_obj.search(cr, uid, domain, context=context) + + if not line_ids: + inventory_line_obj.create(cr, uid, stock_move_details, context=context) + + return {'type': 'ir.actions.act_window_close'} + +stock_fill_inventory() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_inventory_extended/wizard/stock_fill_inventory_view.xml b/stock_inventory_extended/wizard/stock_fill_inventory_view.xml new file mode 100644 index 000000000..7fd20b284 --- /dev/null +++ b/stock_inventory_extended/wizard/stock_fill_inventory_view.xml @@ -0,0 +1,48 @@ + + + + + Import Inventory + stock.fill.inventory2 + form + +
+ + + + + + + + + + +
+ + + {'full':'1', 'type':'normal'} + [('type', '=', 'normal')] + + + + [('state','=','draft'), ('type', '=', 'normal')] + + + + Move stock + ir.actions.act_window + stock.inventory + form + + {'full':'1', '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 000000000..4096c452a --- /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 000000000..a27155d2a --- /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 000000000..88c70a085 --- /dev/null +++ b/stock_move_location/wizard/move_location_view.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/stock_move_on_hold/__init__.py b/stock_move_on_hold/__init__.py new file mode 100644 index 000000000..9bcda880d --- /dev/null +++ b/stock_move_on_hold/__init__.py @@ -0,0 +1,26 @@ +# -*- 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 invoice +import product + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_move_on_hold/__openerp__.py b/stock_move_on_hold/__openerp__.py new file mode 100644 index 000000000..81c07d2aa --- /dev/null +++ b/stock_move_on_hold/__openerp__.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 . +# +################################################################################# + +{ + "name" : "Stock On Hold Status", + "version" : "1.0", + "author" : "Julius Network Solutions", + "description" : """ This Module allows to hold pickings. + It's adding a button which holding the picking and workflow. + You should use the sale_prepayment module to be automated with sale orders and invoices. + """, + "website" : "http://www.julius.fr", + "depends" : [ + "stock", + ], + "category" : "Stock", + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + 'wizard/stock_invoice_onshipping_view.xml', + 'stock_view.xml', + 'stock_workflow.xml', + ], + 'test': [], + 'installable': True, + 'active': False, + 'certificate': '', +} diff --git a/stock_move_on_hold/invoice.py b/stock_move_on_hold/invoice.py new file mode 100644 index 000000000..2640fddf3 --- /dev/null +++ b/stock_move_on_hold/invoice.py @@ -0,0 +1,57 @@ +# -*- 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 account_invoice(osv.osv): + + _inherit = 'account.invoice' + + def confirm_paid(self, cr, uid, ids, context=None): + if context is None: + context = {} + super(account_invoice, self).confirm_paid(cr, uid, ids, context) + cr.execute("""SELECT order_id FROM sale_order_invoice_rel WHERE invoice_id in %s """, (tuple(ids),)) + order_ids = map(lambda x: x[0], cr.fetchall()) + self.pool.get('sale.order').write(cr, uid, order_ids, {}) + cr.execute("""SELECT id FROM stock_picking where state = 'on_hold_paym' and sale_id in (SELECT order_id FROM sale_order_invoice_rel WHERE invoice_id in %s) """, (tuple(ids),)) + pickings = map(lambda x: x[0], cr.fetchall()) + self.pool.get('stock.picking').action_assign(cr, uid, pickings) + return True + + _columns = { + 'is_advance': fields.boolean('Is an advance?'), + } + +account_invoice() + +class account_invoice_line(osv.osv): + + _inherit = 'account.invoice.line' + + _columns = { + 'is_advance': fields.boolean('Is an advance?'), + } + +account_invoice_line() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_move_on_hold/product.py b/stock_move_on_hold/product.py new file mode 100644 index 000000000..ccf8c4260 --- /dev/null +++ b/stock_move_on_hold/product.py @@ -0,0 +1,60 @@ +# -*- 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 _ +import decimal_precision as dp + +class product_product(osv.osv): + + _inherit = "product.product" + + def _product_available(self, cr, uid, ids, field_names=None, arg=False, context={}): + if not field_names: + field_names = [] + res = {} + for id in ids: + res[id] = {}.fromkeys(field_names, 0.0) + for f in field_names: + c = context.copy() + if f == 'qty_available': + c.update({ 'states':('done',), 'what':('in', 'out') }) + if f == 'virtual_available': + c.update({ 'states':('confirmed','waiting','assigned','on_hold','on_hold_billing','on_hold_paym','done'), 'what':('in', 'out') }) + if f == 'incoming_qty': + c.update({ 'states':('confirmed','waiting','assigned','on_hold','on_hold_billing','on_hold_paym'), 'what':('in',) }) + if f == 'outgoing_qty': + c.update({ 'states':('confirmed','waiting','assigned','on_hold','on_hold_billing','on_hold_paym'), 'what':('out',) }) + stock = self.get_product_available(cr,uid,ids,context=c) + for id in ids: + res[id][f] = stock.get(id, 0.0) + return res + + _columns = { + 'qty_available': fields.function(_product_available, method=True, type='float', string='Real Stock', help="Current quantities of products in selected locations or all internal if none have been selected.", multi='qty_available', digits_compute=dp.get_precision('Product UoM')), + 'virtual_available': fields.function(_product_available, method=True, type='float', string='Virtual Stock', help="Future stock for this product according to the selected location or all internal if none have been selected. Computed as: Real Stock - Outgoing + Incoming.", multi='qty_available', digits_compute=dp.get_precision('Product UoM')), + 'incoming_qty': fields.function(_product_available, method=True, type='float', string='Incoming', help="Quantities of products that are planned to arrive in selected locations or all internal if none have been selected.", multi='qty_available', digits_compute=dp.get_precision('Product UoM')), + 'outgoing_qty': fields.function(_product_available, method=True, type='float', string='Outgoing', help="Quantities of products that are planned to leave in selected locations or all internal if none have been selected.", multi='qty_available', digits_compute=dp.get_precision('Product UoM')), + } + +product_product() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_move_on_hold/stock.py b/stock_move_on_hold/stock.py new file mode 100644 index 000000000..7b3d9220b --- /dev/null +++ b/stock_move_on_hold/stock.py @@ -0,0 +1,582 @@ +# -*- 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 datetime import datetime +from osv import fields, osv +from tools.translate import _ +import netsvc + +# ---------------------------------------------------- +# Move +# ---------------------------------------------------- + +# +# Fields: +# location_dest_id is only used for predicting future stocks +# +class stock_move(osv.osv): + + _inherit = 'stock.move' + + _columns = { + 'state': fields.selection([ + ('draft', 'Draft'), + ('waiting', 'Waiting'), + ('on_hold', 'Waiting for prepayment'), + ('on_hold_billing', 'Waiting for billing'), + ('on_hold_paym', 'Waiting for payment'), + ('confirmed', 'Not Available'), + ('assigned', 'Available'), + ('done', 'Done'), + ('cancel', 'Cancelled') + ], 'State', readonly=True, select=True, + help="* When the stock move is created it is in the \'Draft\' state.\n"\ + "* After that, it is set to \'Not Available\' state if the scheduler did not find the products.\n"\ + "* When products are reserved it is set to \'Available\'.\n"\ + "* When the picking is done the state is \'Done\'.\n"\ + "* The state is \'Waiting\' if the move is waiting for another one.\n"\ + "* The state is \'Waiting for prepayment\' if it's waiting for a prepayment of the sale order\n"\ + "* The state is \'Waiting for billing\' if it's waiting for billing of the move\n"\ + "* The state is \'Waiting for payment\' if it's waiting for the payment of the move"), + } + + def action_on_hold(self, cr, uid, ids, context=None): + """ Holds stock move. + @return: List of ids. + """ + moves = self.browse(cr, uid, ids, context=context) + self.write(cr, uid, ids, {'state': 'on_hold'}) + + if moves: + picking = moves[0].picking_id + if picking: + moves = picking.move_lines + state = 'on_hold' + for move in moves: + if move.state not in ['on_hold','done','cancel']: + state = False + break + if state: + self.pool.get('stock.picking').write(cr, uid, picking.id, {'state': state}, context) + return [] + + def action_hold_to_confirm(self, cr, uid, ids, context=None): + """ Makes hold stock moves to the confirmed state. + @return: List of ids. + """ + moves = self.browse(cr, uid, ids, context=context) + self.write(cr, uid, ids, {'state': 'confirmed'}) + + if moves: + picking = moves[0].picking_id + if picking: + moves = picking.move_lines + state = 'confirmed' + for move in moves: + if move.state in ['on_hold','draft']: + state = False + break + if state: + self.pool.get('stock.picking').write(cr, uid, picking.id, {'state': state}, context) + return [] + + def action_confirm_waiting_bill(self, cr, uid, ids, context=None): + """ Makes hold stock moves to the wait for billing state. + @return: List of ids. + """ + moves = self.browse(cr, uid, ids, context=context) + self.write(cr, uid, ids, {'state': 'on_hold_billing'}) + + if moves: + picking = moves[0].picking_id + if picking: + moves = picking.move_lines + state = 'on_hold_billing' + for move in moves: + if move.state in ['on_hold','draft']: + state = False + break + if state: + self.pool.get('stock.picking').write(cr, uid, picking.id, {'state': state}, context) + return [] + + def action_waiting_bill_to_unpaid(self, cr, uid, ids, context=None): + """ Makes hold stock moves to the wait for payment state. + @return: List of ids. + """ + moves = self.browse(cr, uid, ids, context=context) + + if moves: + picking = moves[0].picking_id + if picking: + moves = picking.move_lines + state = 'on_hold_paym' + for move in moves: + if move.state in ['on_hold','draft']: + state = False + break + if state: + self.pool.get('stock.picking').write(cr, uid, picking.id, {'state': state}, context) + return [] + + """ This part is replacing the usual one to be able to taking in account the new states. """ + def action_assign(self, cr, uid, ids, *args): + """ Changes state to confirmed or waiting. + @return: List of values + """ + todo = [] + for move in self.browse(cr, uid, ids): + if move.state in ('confirmed', 'waiting', 'on_hold_billing', 'on_hold_paym', 'assigned'): + todo.append(move.id) + res = self.check_assign(cr, uid, todo) + return res + + """ This part is replacing the usual one to be able to taking in account the new states. """ + def check_assign(self, cr, uid, ids, context=None): + """ Checks the product type and accordingly writes the state. + @return: No. of moves done + """ + done = [] + count = 0 + waiting = 0 + pickings = {} + if context is None: + context = {} + for move in self.browse(cr, uid, ids, context=context): + if move.product_id.type == 'consu' or move.location_id.usage == 'supplier': + if move.state in ('confirmed', 'waiting'): + done.append(move.id) + pickings[move.picking_id.id] = 1 + continue + if move.state in ('confirmed', 'waiting', 'on_hold_billing', 'on_hold_paym'): + if move.state in ('on_hold_billing', 'on_hold_paym'): + res = True + else: + # Important: we must pass lock=True to _product_reserve() to avoid race conditions and double reservations + res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, {'uom': move.product_uom.id}, lock=True) + if res: + if move.sale_line_id and move.sale_line_id.order_id.order_policy in ['ship_prepayment','wait_prepayment']: + if not move.sale_line_id.invoice_lines: + self.write(cr, uid, [move.id], {'state':'on_hold_billing'}) + pickings[move.picking_id.id] = 1 + waiting += 1 + else: + for line in move.sale_line_id.invoice_lines: + if line.invoice_id and line.invoice_id.state == 'cancel': + self.write(cr, uid, [move.id], {'state':'on_hold_billing'}) + pickings[move.picking_id.id] = 1 + waiting += 1 + elif line.invoice_id and line.invoice_id.state != 'paid': + self.write(cr, uid, [move.id], {'state':'on_hold_paym'}) + pickings[move.picking_id.id] = 1 + waiting += 1 + elif line.invoice_id and line.invoice_id.state == 'paid': + self.write(cr, uid, [move.id], {'state':'assigned'}) + pickings[move.picking_id.id] = 1 + waiting += 1 + #_product_available_test depends on the next status for correct functioning + #the test does not work correctly if the same product occurs multiple times + #in the same order. This is e.g. the case when using the button 'split in two' of + #the stock outgoing form + elif res != True: + self.write(cr, uid, [move.id], {'state':'assigned'}) + done.append(move.id) + pickings[move.picking_id.id] = 1 + r = res.pop(0) + cr.execute('update stock_move set location_id=%s, product_qty=%s where id=%s', (r[1], r[0], move.id)) + + while res: + r = res.pop(0) + move_id = self.copy(cr, uid, move.id, {'product_qty': r[0], 'location_id': r[1]}) + done.append(move_id) + if done: + count += len(done) + self.write(cr, uid, done, {'state': 'assigned'}) + + if count or waiting: + for pick_id in pickings: + wf_service = netsvc.LocalService("workflow") + wf_service.trg_write(uid, 'stock.picking', pick_id, cr) + return count + +stock_move() + +class stock_picking(osv.osv): + + _inherit = 'stock.picking' + + _columns = { + 'state': fields.selection([ + ('draft', 'Draft'), + ('auto', 'Waiting'), + ('on_hold', 'Waiting for prepayment'), + ('on_hold_billing', 'Waiting for billing'), + ('on_hold_paym', 'Waiting for payment'), + ('confirmed', 'Confirmed'), + ('assigned', 'Available'), + ('done', 'Done'), + ('cancel', 'Cancelled'), + ], 'State', readonly=True, select=True, + help="* Draft: not confirmed yet and will not be scheduled until confirmed\n"\ + "* Confirmed: still waiting for the availability of products\n"\ + "* Waiting: waiting for another move to proceed before it becomes automatically available (e.g. in Make-To-Order flows)\n"\ + "* On Hold: waiting for a payment, payment or billing\n"\ + "* Waiting for billing: waiting for billing of the picking\n"\ + "* Waiting for payment: waiting for the payment of the picking\n"\ + "* Available: products reserved, simply waiting for confirmation.\n"\ + "* Done: has been processed, can't be modified or cancelled anymore\n"\ + "* Cancelled: has been cancelled, can't be confirmed anymore"), + } + + def action_on_hold(self, cr, uid, ids, context=None): + """ Holds picking. + @return: True + """ + self.write(cr, uid, ids, {'state': 'on_hold'}) + todo = [] + for picking in self.browse(cr, uid, ids, context=context): + for r in picking.move_lines: + if r.state in ['draft','confirmed','waiting','assigned','on_hold_billing','on_hold_paym']: + todo.append(r.id) + + self.log_picking(cr, uid, ids, context=context) + + todo = self.action_explode(cr, uid, todo, context) + if len(todo): + self.pool.get('stock.move').action_on_hold(cr, uid, todo, context=context) + return True + + def action_hold_to_confirm(self, cr, uid, ids, context=None): + """ Makes hold pickings to the confirmed state. + @return: True + """ + self.write(cr, uid, ids, {'state': 'confirmed'}) + todo = [] + for picking in self.browse(cr, uid, ids, context=context): + for r in picking.move_lines: + if r.state in ['on_hold']: + todo.append(r.id) + + self.log_picking(cr, uid, ids, context=context) + + todo = self.action_explode(cr, uid, todo, context) + if len(todo): + self.pool.get('stock.move').action_hold_to_confirm(cr, uid, todo, context=context) + return True + + def action_confirm_waiting_bill(self, cr, uid, ids, context=None): + """ Makes hold pickings to the wait for billing state. + @return: True + """ + self.write(cr, uid, ids, {'state': 'on_hold_billing', 'invoice_state': '2binvoiced'}) + todo = [] + for picking in self.browse(cr, uid, ids, context=context): + for r in picking.move_lines: + if r.state in ['on_hold_billing']: + todo.append(r.id) + + self.log_picking(cr, uid, ids, context=context) + + todo = self.action_explode(cr, uid, todo, context) + if len(todo): + self.pool.get('stock.move').action_confirm_waiting_bill(cr, uid, todo, context=context) + return True + + def action_waiting_bill_to_unpaid(self, cr, uid, ids, context=None): + """ Makes hold pickings to the wait for payment state. + @return: True + """ + self.write(cr, uid, ids, {'state': 'on_hold_paym'}) + todo = [] + for picking in self.browse(cr, uid, ids, context=context): + for r in picking.move_lines: + if r.state in ['on_hold_paym']: + todo.append(r.id) + + self.log_picking(cr, uid, ids, context=context) + + todo = self.action_explode(cr, uid, todo, context) + if len(todo): + self.pool.get('stock.move').action_waiting_bill_to_unpaid(cr, uid, todo, context=context) + return True + + """ This part is replacing the usual one to be able to taking in account the new states. """ + def action_assign(self, cr, uid, ids, *args): + """ Changes state of picking to available if all moves are confirmed. + @return: True + """ + for pick in self.browse(cr, uid, ids): + move_ids = [x.id for x in pick.move_lines if x.state in ['confirmed','on_hold_billing','on_hold_paym']] + if not move_ids: + raise osv.except_osv(_('Warning !'),_('Not enough stock, unable to reserve the products.')) + self.pool.get('stock.move').action_assign(cr, uid, move_ids) + return True + + def test_billed(self, cr, uid, ids): + """ Tests whether the move has been billed or not. + @return: True or False + """ + ok = True + for pick in self.browse(cr, uid, ids): + mt = pick.move_type + for move in pick.move_lines: + if (move.state in ('confirmed', 'draft')) and (mt == 'one'): + return False + if (mt == 'direct') and (move.state == 'on_hold_billing') and (move.product_qty): + return True + ok = ok and (move.state in ('cancel', 'done', 'assigned', 'on_hold_paym')) + return ok + + def test_bill_and_paid(self, cr, uid, ids): + """ Tests whether the move has been billed and paid or not. + @return: True or False + """ + ok = True + for pick in self.browse(cr, uid, ids): + mt = pick.move_type + for move in pick.move_lines: + if (move.state in ('confirmed', 'draft', 'on_hold', 'on_hold_billing')) and (mt == 'one'): + return False + if (mt == 'direct') and (move.state == 'on_hold_paym') and (move.product_qty): + return True + ok = ok and (move.state in ('cancel', 'done', 'assigned')) + return ok + + def test_paid(self, cr, uid, ids): + """ Tests whether the move has been paid. + @return: True or False + """ + ok = True + for pick in self.browse(cr, uid, ids): + mt = pick.move_type + for move in pick.move_lines: + if (move.state in ('confirmed', 'draft', 'on_hold', 'on_hold_billing', 'on_hold_paym')) and (mt == 'one'): + return False + if (mt == 'direct') and (move.state == 'assigned') and (move.product_qty): + return True + ok = ok and (move.state in ('cancel', 'done', 'assigned')) + return ok + + """ This part is replacing the usual one to be able to taking in account the new states. """ + def log_picking(self, cr, uid, ids, context=None): + """ This function will create log messages for picking. + @param cr: the database cursor + @param uid: the current user's ID for security checks, + @param ids: List of Picking Ids + @param context: A standard dictionary for contextual values + """ + if context is None: + context = {} + data_obj = self.pool.get('ir.model.data') + for pick in self.browse(cr, uid, ids, context=context): + msg='' + if pick.auto_picking: + continue + type_list = { + 'out':_("Delivery Order"), + 'in':_('Reception'), + 'internal': _('Internal picking'), + } + view_list = { + 'out': 'view_picking_out_form', + 'in': 'view_picking_in_form', + 'internal': 'view_picking_form', + } + message = type_list.get(pick.type, _('Document')) + " '" + (pick.name or '?') + "' " + if pick.min_date: + msg= _(' for the ')+ datetime.strptime(pick.min_date, '%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y') + state_list = { + 'confirmed': _("is scheduled") + msg +'.', + 'assigned': _('is ready to process.'), + 'cancel': _('is cancelled.'), + 'done': _('is done.'), + 'draft': _('is in draft state.'), + 'auto': _('is waiting.'), + 'on_hold': _('is hold, waiting for prepayment.'), + 'on_hold_billing': _('is ready to process but waiting for a billing.'), + 'on_hold_paym': _('is ready to process but waiting for the payment.'), + } + res = data_obj.get_object_reference(cr, uid, 'stock', view_list.get(pick.type, 'view_picking_form')) + context.update({'view_id': res and res[1] or False}) + message += state_list[pick.state] + self.log(cr, uid, pick.id, message, context=context) + return True + + def already_invoiced(self, cr, uid, ids, pick_invoice, context=None): + """ Looking for what have already been invoice to deduce it on the new invoice """ + invoice_obj = self.pool.get('account.invoice') + sale_obj = self.pool.get('sale.order') + picking_ids = self.browse(cr, uid, ids, context) + res = {} + for pick in picking_ids: + sale_id = pick.sale_id and pick.sale_id.id + if sale_id: + amount_prepaid = 0.00 + amount_total = 0.00 + cr.execute("""SELECT invoice_id FROM sale_order_invoice_rel WHERE order_id = %s """, (sale_id,)) + invoice_ids = map(lambda x: x[0], cr.fetchall()) + invoice_open_paid = invoice_obj.search(cr, uid, [('id', 'in', invoice_ids),('state', 'in', ['open','paid'])]) + invoice_id = pick_invoice[pick.id] + res[invoice_id] = invoice_open_paid + for invoice in invoice_obj.browse(cr, uid, invoice_open_paid): + if invoice.is_advance: + amount_prepaid += invoice.amount_untaxed or 0.00 + else: + for line in invoice.invoice_line: + if not line.is_advance: + amount_total += line.price_subtotal or 0.00 + sale_obj.write(cr, uid, [sale_id], {'amount_prepaid': amount_prepaid, 'amount_shipped': amount_total}) + return res + + def create_advance_line(self, cr, uid, pick_invoice, invoice_done, context=None): + invoice_obj = self.pool.get('account.invoice') + account_line_obj = self.pool.get('account.invoice.line') + for pick in pick_invoice: + picking_id = self.browse(cr, uid, pick, context) + sale_id = picking_id.sale_id + total_amount = sale_id.amount_untaxed or 0.00 + prepaid_amount = sale_id.amount_prepaid or 0.00 + amount_shipped = sale_id.amount_shipped or 0.00 + invoice_id = pick_invoice[pick] + invoice_id = invoice_obj.browse(cr, uid, invoice_id) + invoice_amount = invoice_id.amount_untaxed + if prepaid_amount >= amount_shipped: + if (invoice_amount + amount_shipped) > prepaid_amount: + line_amount = - (prepaid_amount - amount_shipped) + else: + line_amount = - invoice_amount + res = account_line_obj.product_id_change(cr, uid, [], 7624, False, 1, partner_id=invoice_id.partner_id.id, fposition_id=invoice_id.fiscal_position.id, price_unit=line_amount, address_invoice_id=invoice_id.address_invoice_id.id, currency_id=invoice_id.currency_id.id, context=context) + account_line_obj = self.pool.get('account.invoice.line') + vals = res['value'] + vals.update({'invoice_id': invoice_id.id, 'invoice_line_tax_id': [(6, 0, vals['invoice_line_tax_id'])], 'note':'', 'price_unit': line_amount, 'is_advance': True}) + if vals['price_unit'] <> 0: + account_line_obj.create(cr, uid, vals) + invoice_amount = invoice_id.amount_untaxed + if sale_id: + self.pool.get('sale.order').write(cr, uid, [sale_id.id], {'amount_shipped': amount_shipped + invoice_amount}) + invoice_obj.button_reset_taxes(cr, uid, [invoice_id.id], context=context) + return + + def associate_lines(self, cr, uid, ids, pick_invoice, context): + inv_line_obj = self.pool.get('account.invoice.line') + move_line_obj = self.pool.get('stock.move') + for pick in pick_invoice: + picking_id = self.browse(cr, uid, pick, context) + invoice_id = pick_invoice[pick] + move_lines = picking_id.move_lines + for line in move_lines: + invoice_line_ids = inv_line_obj(cr, uid, [ + ('invoice_id', '=', invoice_id), + ('product_id', '=', line.product_id.id), + ('quantity', '=', line.product_qty), + ]) + if invoice_line_ids: + move_line_obj.write(cr, uid, [line.id], {'invoice_line_id': invoice_line_ids[0]}) + + def action_invoice_create(self, cr, uid, ids, journal_id=False, + group=False, type='out_invoice', context=None): + if context is None: + context = {} + if context.get('before_shipping', False): + picking_ids = self.browse(cr, uid, ids) + todo = [] + sequence_obj = self.pool.get('ir.sequence') + for pick in picking_ids: + line_ids = [x.id for x in pick.move_lines if x.state == 'on_hold_billing'] + old_lines_ids = [x.id for x in pick.move_lines if x.id not in line_ids] + if line_ids: + wf_service = netsvc.LocalService("workflow") + if old_lines_ids: + new_picking = self.copy(cr, uid, pick.id, + { + 'name': sequence_obj.get(cr, uid, 'stock.picking.%s'%(pick.type)), + 'move_lines' : [], + 'state':'confirmed', + 'backorder_id': pick.id, + }) + self.pool.get('stock.move').write(cr, uid, old_lines_ids, {'picking_id': new_picking}), + wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_confirm', cr) + self.pool.get('stock.move').write(cr, uid, line_ids, {'state': 'on_hold_paym'}), + todo.append(pick.id) + ids = todo + res = super(stock_picking, self).action_invoice_create(cr, uid, ids, journal_id, group, type, context) + invoice_done = self.already_invoiced(cr, uid, ids, res, context) + self.create_advance_line(cr, uid, res, invoice_done, context) + return res + +stock_picking() + +class stock_location(osv.osv): + + _inherit = "stock.location" + + def _product_reserve(self, cr, uid, ids, product_id, product_qty, context=None, lock=False): + result = super(stock_location, self)._product_reserve(cr, uid, ids, product_id, product_qty, context, lock) + if context is None: + context = {} + result = [] + for id in self.search(cr, uid, [('location_id', 'child_of', ids)]): + cr.execute("""SELECT product_uom, sum(product_qty) AS product_qty + FROM stock_move + WHERE location_dest_id=%s AND + location_id<>%s AND + product_id=%s AND + state='done' + GROUP BY product_uom + """, + (id, id, product_id)) + results = cr.dictfetchall() + cr.execute("""SELECT product_uom,-sum(product_qty) AS product_qty + FROM stock_move + WHERE location_id=%s AND + location_dest_id<>%s AND + product_id=%s AND + state in ('done', 'assigned', 'on_hold_billing', 'on_hold_paym') + GROUP BY product_uom + """, + (id, id, product_id)) + results += cr.dictfetchall() + total = 0.0 + results2 = 0.0 + for r in results: + amount = self.pool.get('product.uom')._compute_qty(cr, uid, r['product_uom'], r['product_qty'], context.get('uom', False)) + results2 += amount + total += amount + + if total <= 0.0: + continue + + amount = results2 + if amount > 0: + if amount > min(total, product_qty): + amount = min(product_qty, total) + result.append((amount, id)) + product_qty -= amount + total -= amount + if product_qty <= 0.0: + return result + if total <= 0.0: + continue + return False + +stock_location() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_move_on_hold/stock_view.xml b/stock_move_on_hold/stock_view.xml new file mode 100644 index 000000000..985ccb47e --- /dev/null +++ b/stock_move_on_hold/stock_view.xml @@ -0,0 +1,139 @@ + + + + + + + + stock.move.outgoing.search2.inherit + stock.move + search + + + + + + + + + + stock.picking.out.form.inherit + stock.picking + form + + + + + + + + + + stock.picking.list.select.inherit + stock.picking + search + + + + + + + + + + stock.picking.out.search.inherit + stock.picking + search + + + + + + + + + + diff --git a/stock_move_on_hold/stock_workflow.xml b/stock_move_on_hold/stock_workflow.xml new file mode 100644 index 000000000..996cd2717 --- /dev/null +++ b/stock_move_on_hold/stock_workflow.xml @@ -0,0 +1,103 @@ + + + + + + + on_hold + function + action_on_hold() + + + + + + button_on_hold + + + + + button_on_hold + + + + + button_on_hold + + + + + unhold + function + action_hold_to_confirm() + + + + + unbilled + function + action_confirm_waiting_bill() + + + + + unpaid + function + action_waiting_bill_to_unpaid() + + + + + + button_unhold + + + + + + test_assigned() + + + + + + + + + + + test_billed() + + + + + + test_bill_and_paid() + + + + + + not test_bill_and_paid() + + + + + + test_paid() + + + + + + allow_cancel() + button_cancel + + + + + test_cancel() + + + + diff --git a/stock_move_on_hold/wizard/stock_invoice_onshipping_view.xml b/stock_move_on_hold/wizard/stock_invoice_onshipping_view.xml new file mode 100644 index 000000000..612ffbc57 --- /dev/null +++ b/stock_move_on_hold/wizard/stock_invoice_onshipping_view.xml @@ -0,0 +1,35 @@ + + + + + + Stock Invoice Onshipping + stock.invoice.onshipping + form + +
+ + + + + + + + + +
+ +
+
diff --git a/stock_tracking_add_move/__init__.py b/stock_tracking_add_move/__init__.py new file mode 100644 index 000000000..c2c2ebef6 --- /dev/null +++ b/stock_tracking_add_move/__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_tracking_add_move/__openerp__.py b/stock_tracking_add_move/__openerp__.py new file mode 100644 index 000000000..f7027b189 --- /dev/null +++ b/stock_tracking_add_move/__openerp__.py @@ -0,0 +1,45 @@ +# -*- 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" : "Stock tracking add moves", + "version" : "1.0", + "author" : "Julius Network Solutions", + "description" : """ This module add a wizard to fill in packaging """, + "website" : "http://www.julius.fr", + "depends" : [ + "stock", + "stock_tracking_extended", + "tr_barcode", + ], + "category" : "Customs/Stock", + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + 'wizard/add_move_view.xml', + 'stock_view.xml', + "security/ir.model.access.csv", + ], + 'test': [], + 'installable': True, + 'active': False, + 'certificate': '', +} diff --git a/stock_tracking_add_move/i18n/fr.po b/stock_tracking_add_move/i18n/fr.po new file mode 100644 index 000000000..d224faac6 --- /dev/null +++ b/stock_tracking_add_move/i18n/fr.po @@ -0,0 +1,145 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * stock_tracking_add_move +# +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:45+0000\n" +"PO-Revision-Date: 2011-12-19 10:45+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_tracking_add_move +#: field:stock.packaging.move,pack_id:0 +msgid "Pack to move" +msgstr "Pack à déplacer" + +#. module: stock_tracking_add_move +#: model:ir.module.module,description:stock_tracking_add_move.module_meta_information +msgid " This module add a wizard to fill in packaging " +msgstr " Ce module ajoute un assistant pour remplir les pack " + +#. module: stock_tracking_add_move +#: field:stock.scan.to.validate,type:0 +msgid "Type" +msgstr "Type" + +#. module: stock_tracking_add_move +#: view:stock.packaging.move:0 +msgid "Add Move" +msgstr "Ajouter des mouvements" + +#. module: stock_tracking_add_move +#: selection:stock.scan.to.validate,type:0 +msgid "To remove" +msgstr "A supprimer" + +#. module: stock_tracking_add_move +#: field:stock.scan.to.validate,tracking_id:0 +msgid "Parent" +msgstr "Parent" + +#. module: stock_tracking_add_move +#: model:ir.model,name:stock_tracking_add_move.model_stock_tracking +msgid "Packs" +msgstr "Pack" + +#. module: stock_tracking_add_move +#: sql_constraint:stock.scan.to.validate:0 +msgid "This barcode is already in the list to add or to remove !" +msgstr "Ce code-barres est déjà dans la liste à ajouter ou à enlever !" + +#. module: stock_tracking_add_move +#: constraint:stock.tracking:0 +msgid "Bad parent type selection. Please try again." +msgstr "Mauvais choix du type de parent. S'il vous plaît essayez de nouveau." + +#. module: stock_tracking_add_move +#: field:stock.scan.to.validate,barcode_id:0 +msgid "Barcode" +msgstr "code-barres" + +#. module: stock_tracking_add_move +#: selection:stock.scan.to.validate,type:0 +#: field:stock.tracking,to_add:0 +msgid "To add" +msgstr "A ajouter" + +#. module: stock_tracking_add_move +#: field:stock.tracking.history,parent_id:0 +msgid "Parent pack" +msgstr "Pack parent" + +#. module: stock_tracking_add_move +#: model:ir.actions.act_window,name:stock_tracking_add_move.pack_remove_move +#: view:stock.tracking:0 +msgid "Remove object" +msgstr "Retirer l'objet" + +#. module: stock_tracking_add_move +#: model:ir.module.module,shortdesc:stock_tracking_add_move.module_meta_information +msgid "Stock tracking add moves" +msgstr "Le suivi du stock ajoute des mouvements" + +#. module: stock_tracking_add_move +#: model:ir.actions.act_window,name:stock_tracking_add_move.pack_add_move +#: view:stock.tracking:0 +msgid "Add object" +msgstr "Ajouter un objet" + +#. module: stock_tracking_add_move +#: model:ir.model,name:stock_tracking_add_move.model_stock_tracking_history +msgid "stock.tracking.history" +msgstr "stock.tracking.history" + +#. module: stock_tracking_add_move +#: view:stock.packaging.move:0 +msgid "Remove Move" +msgstr "Retirer mouvement" + +#. module: stock_tracking_add_move +#: model:ir.model,name:stock_tracking_add_move.model_stock_packaging_move +msgid "stock.packaging.move" +msgstr "stock.packaging.move" + +#. module: stock_tracking_add_move +#: view:stock.scan.to.validate:0 +#: field:stock.tracking,to_remove:0 +msgid "To validate" +msgstr "Valider" + +#. module: stock_tracking_add_move +#: model:ir.model,name:stock_tracking_add_move.model_stock_scan_to_validate +msgid "stock.scan.to.validate" +msgstr "stock.scan.to.validate" + +#. module: stock_tracking_add_move +#: field:stock.packaging.move,reference:0 +msgid "Reference" +msgstr "Référence" + +#. module: stock_tracking_add_move +#: code:addons/stock_tracking_add_move/stock.py:97 +#: code:addons/stock_tracking_add_move/stock.py:142 +#, python-format +msgid "Barcode Not found!" +msgstr "Code-barres introuvable!" + +#. module: stock_tracking_add_move +#: code:addons/stock_tracking_add_move/stock.py:97 +#: code:addons/stock_tracking_add_move/stock.py:142 +#, python-format +msgid "Warning!" +msgstr "Attention!" + +#. module: stock_tracking_add_move +#: view:stock.packaging.move:0 +msgid "Cancel" +msgstr "Annuler" + diff --git a/stock_tracking_add_move/security/ir.model.access.csv b/stock_tracking_add_move/security/ir.model.access.csv new file mode 100644 index 000000000..faa142595 --- /dev/null +++ b/stock_tracking_add_move/security/ir.model.access.csv @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_stock_scan_to_validate_user","stock.scan.to.validate user","model_stock_scan_to_validate","stock.group_stock_user",1,1,1,1 +"access_stock_scan_to_validate_manager","stock.scan.to.validate manager","model_stock_scan_to_validate","stock.group_stock_manager",1,1,1,1 diff --git a/stock_tracking_add_move/stock.py b/stock_tracking_add_move/stock.py new file mode 100644 index 000000000..2fe169cb9 --- /dev/null +++ b/stock_tracking_add_move/stock.py @@ -0,0 +1,203 @@ +# -*- 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_tracking(osv.osv): + + _inherit = 'stock.tracking' + + _columns = { + 'parent_id': fields.many2one('stock.tracking', 'Parent', readonly=True), + 'child_ids': fields.one2many('stock.tracking', 'parent_id', 'Children', readonly=True), + 'to_add': fields.one2many('stock.scan.to.validate', 'tracking_id', 'To add', domain=[('type','=','in')]), + 'to_remove': fields.one2many('stock.scan.to.validate', 'tracking_id', 'To validate', domain=[('type','=','out')]), + } + + def add_validation(self, cr, uid, ids, barcode_ids, context=None): + + barcode_obj = self.pool.get('tr.barcode') + tracking_obj = self.pool.get('stock.tracking') + move_obj = self.pool.get('stock.move') + product_obj = self.pool.get('product.product') + history_obj = self.pool.get('stock.tracking.history') + validate_obj = self.pool.get('stock.scan.to.validate') + + if context == None: + context = {} + if barcode_ids: + for obj in self.browse(cr, uid, ids): + barcode = barcode_obj.browse(cr, uid, barcode_ids[0]) + model = barcode.res_model + res_id = barcode.res_id + + if model == 'stock.tracking': + '''Pack Case''' + pack = tracking_obj.browse(cr, uid, res_id) + ''' We can only add a closed pack ''' + if pack.state == 'close': + tracking_obj.write(cr, uid, res_id, {'parent_id': obj.id,}) + history_obj.create(cr, uid, {'type': 'pack_in', + 'tracking_id': res_id, + 'parent_id': obj.id, + }) + tracking_obj.write(cr, uid, pack.id, {'location_id': obj.location_id and obj.location_id.id or False,}) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + for move_data in pack.move_ids: + if move_data.location_dest_id != tracking_obj.browse(cr, uid, obj.id).location_id: + new_move_id = move_obj.create(cr, uid, {'name': move_data.name, + 'state': 'draft', + 'product_id': move_data.product_id.id, + 'product_uom': move_data.product_uom.id, + 'prodlot_id': move_data.prodlot_id.id, + 'location_id': move_data.location_dest_id.id, + 'location_dest_id': obj.location_id.id, + }) + elif model == 'stock.production.lot': + '''Production-lot Case''' + pack = tracking_obj.browse(cr, uid, obj.id) + move_ids = move_obj.search(cr, uid, [('state', '=', 'done'), + ('prodlot_id', '=', res_id), + ('date', '<=', pack.date) +# ('tracking_id', '=', False), +# ('location_dest_id', '=', pack.location_id and pack.location_id.id or False) + ], order='date desc', limit=1) + if move_ids: + move_data = move_obj.browse(cr, uid, move_ids[0]) + if move_data.location_dest_id != pack.location_id: + new_move_id = move_obj.create(cr, uid, {'name': move_data.name, + 'state': 'draft', + 'product_id': move_data.product_id.id, + 'product_uom': move_data.product_uom.id, + 'prodlot_id': move_data.prodlot_id.id, + 'location_id': move_data.location_dest_id.id, + 'location_dest_id': obj.location_id.id, + }) + move_obj.write(cr, uid, new_move_id, {'tracking_id': obj.id}) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + else: + move_obj.write(cr, uid, move_ids, {'tracking_id': obj.id}) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + + elif model == 'product.product': + '''Product Case''' + pack = tracking_obj.browse(cr, uid, obj.id) + product_data = product_obj.browse(cr, uid,res_id) + move_id = move_obj.create(cr, uid, { + 'name': product_data.name, + 'product_id': product_data.id, + 'product_uom': product_data.uom_id.id, + 'location_id': pack.location_id.id, + 'location_dest_id': pack.location_id.id, + 'tracking_id': obj.id, + 'state': 'draft', + }) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + + '''Call for a function who will display serial code list and product list in the pack layout''' + tracking_obj.get_products(cr, uid, ids, context=None) + tracking_obj.get_serials(cr, uid, ids, context=None) + else: + raise osv.except_osv(_('Warning!'),_('Barcode Not found!')) + return {} + + def remove_validation(self, cr, uid, ids, barcode_ids, context=None): + barcode_obj = self.pool.get('tr.barcode') + tracking_obj = self.pool.get('stock.tracking') + move_obj = self.pool.get('stock.move') + product_obj = self.pool.get('product.product') + history_obj = self.pool.get('stock.tracking.history') + validate_obj = self.pool.get('stock.scan.to.validate') + + if context == None: + context = {} + if barcode_ids: + for obj in self.browse(cr, uid, ids): + barcode = barcode_obj.browse(cr, uid, barcode_ids[0]) + model = barcode.res_model + res_id = barcode.res_id + '''Pack Case''' + if model == 'stock.tracking': + pack = tracking_obj.browse(cr, uid, res_id) + tracking_obj.write(cr, uid, res_id, {'parent_id': False}) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + elif model == 'stock.production.lot': + pack = tracking_obj.browse(cr, uid, obj.id) + move_ids = move_obj.search(cr, uid, [ + ('prodlot_id', '=', res_id), + ], limit=1) + if move_ids: + move_obj.write(cr, uid, move_ids, {'tracking_id': False}) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + elif model == 'product.product': + pack = tracking_obj.browse(cr, uid, obj.id) + product_data = product_obj.browse(cr, uid,res_id) + move_ids = move_obj.search(cr, uid, [ + ('product_id', '=', product_data.id), + ], limit=1) + if move_ids: + move_obj.write(cr, uid, move_ids, {'tracking_id': False}) + tracking_obj.write(cr, uid, obj.id, {'modified': True}) + + '''Call for a function who will display serial code list and product list in the pack layout''' + tracking_obj.get_serials(cr, uid, ids, context=None) + tracking_obj.get_products(cr, uid, ids, context=None) + else: + raise osv.except_osv(_('Warning!'),_('Barcode Not found!')) + return {} + +stock_tracking() + +class stock_scan_to_validate(osv.osv): + + _name = 'stock.scan.to.validate' + _columns = { + 'tracking_id': fields.many2one('stock.tracking', 'Parent', readonly=True), + 'type': fields.selection([('in','To add'),('out','To remove')], 'Type', readonly=True), + 'barcode_id': fields.many2one('tr.barcode', 'Barcode', readonly=True), + } + + _sql_constraints = [ + ('tracking_barcode_unique', 'unique (tracking_id,barcode_id)', 'This barcode is already in the list to add or to remove !') + ] + +stock_scan_to_validate() + +class stock_tracking_history(osv.osv): + + _inherit = "stock.tracking.history" + + def _get_types(self, cr, uid, context={}): + res = super(stock_tracking_history, self)._get_types(cr, uid, context) + if not res: + res = [] + res = res + [('pack_in','Add parent'),('pack_out','Unlink parent')] + return res + + _columns = { + 'type': fields.selection(_get_types, 'Type'), + 'parent_id': fields.many2one('stock.tracking', 'Parent pack'), + } + +stock_tracking_history() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_tracking_add_move/stock_view.xml b/stock_tracking_add_move/stock_view.xml new file mode 100644 index 000000000..6fe728f64 --- /dev/null +++ b/stock_tracking_add_move/stock_view.xml @@ -0,0 +1,63 @@ + + + + + + stock.scan.to.validate.tree + stock.scan.to.validate + tree + + + + + + + + + + + + stock.tracking.history.tree + stock.tracking.history + tree + + + + + + + + + + stock.tracking.history.form + stock.tracking.history + form + + + + + + + + + + diff --git a/stock_tracking_add_move/wizard/__init__.py b/stock_tracking_add_move/wizard/__init__.py new file mode 100644 index 000000000..507b428d2 --- /dev/null +++ b/stock_tracking_add_move/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 add_move + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_tracking_add_move/wizard/add_move.py b/stock_tracking_add_move/wizard/add_move.py new file mode 100644 index 000000000..968a4a25d --- /dev/null +++ b/stock_tracking_add_move/wizard/add_move.py @@ -0,0 +1,74 @@ +# -*- 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_packaging_move(osv.osv_memory): + + _name = "stock.packaging.move" + + _columns = { + 'reference': fields.char('Reference', size=128, required=True), + 'pack_id': fields.many2one('stock.tracking', 'Pack to move', required=True), + } + + _defaults = { + 'pack_id': lambda s,cr,uid,c: c.get('active_id',False), + } + + def add_move(self, cr, uid, ids, context=None): + '''Init''' + barcode_obj = self.pool.get('tr.barcode') + tracking_obj = self.pool.get('stock.tracking') + if context == None: + context = {} + + '''Get parent id''' + parent_id = context.get('active_id',False) + for obj in self.browse(cr, uid, ids): + ref = obj.reference + barcode_ids = barcode_obj.search(cr, uid, [('code', '=', ref)], limit=1) + ''' Call for the adding function ''' + tracking_obj.add_validation(cr, uid, [parent_id], barcode_ids, context=None) + return {'type': 'ir.actions.act_window_close'} + + def remove_move(self, cr, uid, ids, context=None): + '''Init''' + barcode_obj = self.pool.get('tr.barcode') + tracking_obj = self.pool.get('stock.tracking') + move_obj = self.pool.get('stock.move') + to_validate_obj = self.pool.get('stock.scan.to.validate') + if context == None: + context = {} + + '''Get parent id''' + parent_id = context.get('active_id',False) + for obj in self.browse(cr, uid, ids): + ref = obj.reference + barcode_ids = barcode_obj.search(cr, uid, [('code', '=', ref)], limit=1) + ''' Call for the removal function ''' + tracking_obj.remove_validation(cr, uid, [parent_id], barcode_ids, context=None) + return {'type': 'ir.actions.act_window_close'} + +stock_packaging_move() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_tracking_add_move/wizard/add_move_view.xml b/stock_tracking_add_move/wizard/add_move_view.xml new file mode 100755 index 000000000..7caaf8991 --- /dev/null +++ b/stock_tracking_add_move/wizard/add_move_view.xml @@ -0,0 +1,82 @@ + + + + + + Add object + stock.packaging.move + form + +
+ + + + + + + + +
+ +
+
diff --git a/stock_tracking_extended/__init__.py b/stock_tracking_extended/__init__.py new file mode 100644 index 000000000..e55343a5d --- /dev/null +++ b/stock_tracking_extended/__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 stock_tracking + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/stock_tracking_extended/__openerp__.py b/stock_tracking_extended/__openerp__.py new file mode 100644 index 000000000..a34a44056 --- /dev/null +++ b/stock_tracking_extended/__openerp__.py @@ -0,0 +1,43 @@ +# -*- 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" : "Stock Packaging extended", + "version" : "1.0", + "author" : "Julius Network Solutions", + "description" : """ This Module allows to have parent/child packaging """, + "website" : "http://www.julius.fr", + "depends" : [ + "stock", + ], + "category" : "Stock", + "init_xml" : [], + "demo_xml" : [], + "update_xml" : [ + 'stock_tracking_view.xml', + 'inventory_sequence.xml', + "security/ir.model.access.csv", + ], + 'test': [], + 'installable': True, + 'active': False, + 'certificate': '', +} diff --git a/stock_tracking_extended/i18n/fr.po b/stock_tracking_extended/i18n/fr.po new file mode 100644 index 000000000..daeb309ab --- /dev/null +++ b/stock_tracking_extended/i18n/fr.po @@ -0,0 +1,279 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * stock_tracking_extended +# +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:42+0000\n" +"PO-Revision-Date: 2011-12-19 10:42+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_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_stock_production_lot +msgid "Production lot" +msgstr "Numéro de série" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_product_stock_tracking +msgid "product.stock.tracking" +msgstr "product.stock.tracking" + +#. module: stock_tracking_extended +#: field:product.ul,capacity_index:0 +msgid "Capacity index" +msgstr "Indice de capacité" + +#. module: stock_tracking_extended +#: constraint:stock.move:0 +msgid "You must assign a production lot for this product" +msgstr "Vous devez affecter un numéro de série pour ce produit." + +#. module: stock_tracking_extended +#: field:stock.tracking,state:0 +msgid "State" +msgstr "Etat" + +#. module: stock_tracking_extended +#: field:stock.production.lot,tracking_id:0 +msgid "pack" +msgstr "Pack" + +#. module: stock_tracking_extended +#: field:stock.tracking,location_id:0 +msgid "Location" +msgstr "Emplacement" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Serial Code" +msgstr "Numéro de série" + +#. module: stock_tracking_extended +#: sql_constraint:stock.production.lot:0 +msgid "The combination of serial number and internal reference must be unique !" +msgstr "La combinaison du numéro de série et de la référence interne doit être unique !" + +#. module: stock_tracking_extended +#: field:stock.tracking.history,type:0 +msgid "Type" +msgstr "Type" + +#. module: stock_tracking_extended +#: code:addons/stock_tracking_extended/stock_tracking.py:118 +#, python-format +msgid "You can't re-open this pack because there is at least one not closed child" +msgstr "Vous ne pouvez pas rouvrir ce pack parce qu'il y a au moins un pack enfant non fermé" + +#. module: stock_tracking_extended +#: field:product.stock.tracking,product_id:0 +#: field:serial.stock.tracking,product_id:0 +msgid "Product" +msgstr "Produit" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_product_category +msgid "Product Category" +msgstr "Catégorie de produits" + +#. module: stock_tracking_extended +#: field:stock.tracking,parent_id:0 +msgid "Parent" +msgstr "Parent" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_stock_tracking +msgid "Packs" +msgstr "Packs" + +#. module: stock_tracking_extended +#: 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 appartient à une autre référence." + +#. module: stock_tracking_extended +#: constraint:stock.tracking:0 +msgid "Bad parent type selection. Please try again." +msgstr "Mauvais choix du type parent. Veuillez ressayez à nouveau." + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Reset Open" +msgstr "Réouvrir" + +#. module: stock_tracking_extended +#: field:product.stock.tracking,quantity:0 +#: field:serial.stock.tracking,quantity:0 +msgid "Quantity" +msgstr "Quantité" + +#. module: stock_tracking_extended +#: code:addons/stock_tracking_extended/stock_tracking.py:113 +#: code:addons/stock_tracking_extended/stock_tracking.py:118 +#: code:addons/stock_tracking_extended/stock_tracking.py:131 +#, python-format +msgid "Not allowed !" +msgstr "Non autorisé !" + +#. module: stock_tracking_extended +#: field:stock.tracking,current_move_ids:0 +msgid "Current moves" +msgstr "Mouvements actuels" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +#: field:stock.tracking,history_ids:0 +#: view:stock.tracking.history:0 +msgid "History" +msgstr "Historique" + +#. module: stock_tracking_extended +#: model:ir.module.module,description:stock_tracking_extended.module_meta_information +msgid " This Module allows to have parent/child packaging " +msgstr " Ce module permet d'avoir des packs parent/enfant " + +#. module: stock_tracking_extended +#: field:product.category,tracked:0 +msgid "Need a serial code ?" +msgstr "Suivre les numéros de série ?" + +#. module: stock_tracking_extended +#: field:product.stock.tracking,tracking_id:0 +#: field:serial.stock.tracking,tracking_id:0 +msgid "Tracking" +msgstr "Suivi" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Downstream traceability" +msgstr "Traçabilité aval" + +#. module: stock_tracking_extended +#: field:stock.tracking,ul_id:0 +msgid "Logistic unit" +msgstr "Unité logistique" + +#. module: stock_tracking_extended +#: model:ir.actions.act_window,name:stock_tracking_extended.action_stock_tracking_tree +#: model:ir.ui.menu,name:stock_tracking_extended.menu_action_stock_tracking_tree +msgid "Packs Structure" +msgstr "Structure de Packs" + +#. module: stock_tracking_extended +#: field:stock.tracking,child_serial_ids:0 +msgid "Child Serials" +msgstr "Numéros de séries enfant" + +#. module: stock_tracking_extended +#: code:addons/stock_tracking_extended/stock_tracking.py:131 +#, python-format +msgid "You can't close this pack because there is at least one not closed child" +msgstr "Vous ne pouvez pas fermer ce pack parce qu'il y a au moins un enfant non fermé" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_stock_tracking_history +msgid "stock.tracking.history" +msgstr "stock.tracking.history" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Update product list" +msgstr "MàJ de la liste de produit" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Child Packs" +msgstr "Packs enfants" + +#. module: stock_tracking_extended +#: view:product.stock.tracking:0 +#: view:serial.stock.tracking:0 +#: view:stock.tracking:0 +#: field:stock.tracking,product_ids:0 +#: field:stock.tracking,serial_ids:0 +msgid "Products" +msgstr "Produits" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Update Serial list" +msgstr "MàJ de la liste des NS" + +#. module: stock_tracking_extended +#: field:stock.tracking.history,tracking_id:0 +msgid "Pack" +msgstr "Pack" + +#. module: stock_tracking_extended +#: model:ir.module.module,shortdesc:stock_tracking_extended.module_meta_information +msgid "Stock Packaging extended" +msgstr "Gestion des packs étendu" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_stock_move +msgid "Stock Move" +msgstr "Mouvement de stock" + +#. module: stock_tracking_extended +#: field:stock.tracking,child_product_ids:0 +msgid "Child Products" +msgstr "Produits enfants" + +#. module: stock_tracking_extended +#: constraint:product.category:0 +msgid "Error ! You can not create recursive categories." +msgstr "Erreur ! Vous ne pouvez pas créer de catégories récursives" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_product_ul +msgid "Shipping Unit" +msgstr "Unité de livraison" + +#. module: stock_tracking_extended +#: code:addons/stock_tracking_extended/stock_tracking.py:113 +#, python-format +msgid "You can't re-open this pack because the parent pack is close" +msgstr "Vous ne pouvez pas ré-ouvrir ce pack, car le pack parent est fermé" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_serial_stock_tracking +msgid "serial.stock.tracking" +msgstr "serial.stock.tracking" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +#: selection:stock.tracking,state:0 +msgid "Close" +msgstr "Fermer" + +#. module: stock_tracking_extended +#: field:serial.stock.tracking,serial_id:0 +msgid "Serial" +msgstr "Série" + +#. module: stock_tracking_extended +#: view:stock.tracking:0 +msgid "Stock Moves" +msgstr "Mouvements de stocks" + +#. module: stock_tracking_extended +#: selection:stock.tracking,state:0 +msgid "Open" +msgstr "Ouvert" + +#. module: stock_tracking_extended +#: field:stock.tracking,child_ids:0 +msgid "Children" +msgstr "Enfant" + +#. module: stock_tracking_extended +#: model:ir.model,name:stock_tracking_extended.model_stock_inventory +msgid "Inventory" +msgstr "Inventaire" + diff --git a/stock_tracking_extended/inventory_sequence.xml b/stock_tracking_extended/inventory_sequence.xml new file mode 100644 index 000000000..d6bf3fc64 --- /dev/null +++ b/stock_tracking_extended/inventory_sequence.xml @@ -0,0 +1,19 @@ + + + + + + + Inventory Order + stock.inventory + + + + Inventory Order + stock.inventory + INV + 3 + + + + diff --git a/stock_tracking_extended/security/ir.model.access.csv b/stock_tracking_extended/security/ir.model.access.csv new file mode 100644 index 000000000..2df41ec2e --- /dev/null +++ b/stock_tracking_extended/security/ir.model.access.csv @@ -0,0 +1,10 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"access_product_stock_tracking_user","product.stock.tracking user","model_product_stock_tracking","stock.group_stock_user",1,1,1,1 +"access_product_stock_tracking_manager","product.stock.tracking manager","model_product_stock_tracking","stock.group_stock_manager",1,1,1,1 +"access_product_stock_tracking_all","product.stock.tracking all","model_product_stock_tracking",,1,0,0,0 +"access_serial_stock_tracking_user","serial.stock.tracking user","model_serial_stock_tracking","stock.group_stock_user",1,1,1,1 +"access_serial_stock_tracking_manager","serial.stock.tracking manager","model_serial_stock_tracking","stock.group_stock_manager",1,1,1,1 +"access_serial_stock_tracking_all","serial.stock.tracking all","model_serial_stock_tracking",,1,0,0,0 +"access_stock_tracking_history_user","serial.stock.tracking user","model_stock_tracking_history","stock.group_stock_user",1,1,1,1 +"access_stock_tracking_history_manager","serial.stock.tracking manager","model_stock_tracking_history","stock.group_stock_manager",1,1,1,1 +"access_stock_tracking_history_all","serial.stock.tracking all","model_stock_tracking_history",,1,0,0,0 diff --git a/stock_tracking_extended/stock_tracking.py b/stock_tracking_extended/stock_tracking.py new file mode 100644 index 000000000..3639fa04c --- /dev/null +++ b/stock_tracking_extended/stock_tracking.py @@ -0,0 +1,316 @@ + # -*- 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 datetime import datetime +from osv import fields, osv +from tools.translate import _ +import netsvc + +class one2many_special(fields.one2many): + def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None): + if not values: + values = {} + res = {} + location_ids = [] + for id in ids: + res[id] = [] + location_id = obj.pool.get('stock.tracking').read(cr, user, id, ['location_id'])['location_id'] + if location_id and location_id[0] and location_id[0] not in location_ids: + location_ids.append(location_id[0]) + ids2 = obj.pool.get(self._obj).search(cr, user, self._domain + [(self._fields_id, 'in', ids), ('location_dest_id', 'in', location_ids)], limit=self._limit) + for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'): + res[r[self._fields_id]].append( r['id'] ) + return res + +class stock_tracking(osv.osv): + + _inherit = 'stock.tracking' + + def hierarchy_ids(self, tracking): + result_list = [tracking] + for child in tracking.child_ids: + result_list.extend(self.hierarchy_ids(child)) + return result_list + + def _get_child_products(self, cr, uid, ids, field_name, arg, context=None): + packs = self.browse(cr, uid, ids) + res = {} + for pack in packs: + res[pack.id] = [] + childs = self.hierarchy_ids(pack) + for child in childs: + for prod in child.product_ids: + res[pack.id].append(prod.id) + return res + + def _get_child_serials(self, cr, uid, ids, field_name, arg, context=None): + packs = self.browse(cr, uid, ids) + res = {} + for pack in packs: + res[pack.id] = [] + childs = self.hierarchy_ids(pack) + for child in childs: + for serial in child.serial_ids: + res[pack.id].append(serial.id) + return res + + _columns = { + 'parent_id': fields.many2one('stock.tracking', 'Parent'), + 'child_ids': fields.one2many('stock.tracking', 'parent_id', 'Children'), + 'ul_id': fields.many2one('product.ul', 'Logistic unit', readonly=True, states={'open':[('readonly',False)]}), + 'location_id': fields.many2one('stock.location', 'Location', required=True, readonly=True, states={'open':[('readonly',False)]}), + 'state': fields.selection([('open','Open'),('close','Close')], 'State', readonly=True), + 'product_ids': fields.one2many('product.stock.tracking', 'tracking_id', 'Products', readonly=True, states={'open':[('readonly',False)]}), + 'child_product_ids': fields.function(_get_child_products, method=True, type='one2many', obj='product.stock.tracking', string='Child Products'), + 'history_ids': fields.one2many('stock.tracking.history', 'tracking_id', 'History'), + 'current_move_ids': one2many_special('stock.move', 'tracking_id', 'Current moves', domain=[('pack_history_id', '=', False)], readonly=True), + 'name': fields.char('Pack Reference', size=64, required=True, readonly=True, states={'open':[('readonly',False)]}), + 'date': fields.datetime('Creation Date', required=True, readonly=True, states={'open':[('readonly',False)]}), + 'serial_ids': fields.one2many('serial.stock.tracking', 'tracking_id', 'Products', readonly=True, states={'open':[('readonly',False)]}), + 'child_serial_ids': fields.function(_get_child_serials, method=True, type='one2many', obj='serial.stock.tracking', string='Child Serials'), + } + + def _check_parent_id(self, cr, uid, ids, context=None): + lines = self.browse(cr, uid, ids, context=context) + + if lines[0].parent_id: + if lines[0].ul_id.capacity_index > lines[0].parent_id.ul_id.capacity_index: + return False + return True + + _constraints = [(_check_parent_id, 'Bad parent type selection. Please try again.',['parent_id'] ),] + + _defaults = { + 'state': 'open', + } + + def reset_open(self, cr, uid, ids, context=None): + pack_ids = self.browse(cr, uid, ids, context) + for pack in pack_ids: + allowed = True + if pack.parent_id: + if pack.parent_id and pack.parent_id != 'open': + self.write(cr, uid, [pack.parent_id.id], {'state': 'open'}) +# allowed = False +# raise osv.except_osv(_('Not allowed !'),_('You can\'t re-open this pack because the parent pack is close')) + if allowed: + for child in pack.child_ids: + if child.state == 'open': + allowed = False + raise osv.except_osv(_('Not allowed !'),_('You can\'t re-open this pack because there is at least one not closed child')) + break + if allowed: + self.write(cr, uid, [pack.id], {'state': 'open'}) + return True + + def set_close(self, cr, uid, ids, context=None): + pack_ids = self.browse(cr, uid, ids, context) + for pack in pack_ids: + allowed = True + for child in pack.child_ids: + if child.state == 'open': + allowed = False + raise osv.except_osv(_('Not allowed !'),_('You can\'t close this pack because there is at least one not closed child')) + break +# if allowed: +# self.write(cr, uid, [pack.id], {'state': 'close'}) + return True + + def get_products(self, cr, uid, ids, context=None): + pack_ids = self.browse(cr, uid, ids, context) + stock_track = self.pool.get('product.stock.tracking') + for pack in pack_ids: + childs = self.hierarchy_ids(pack) + for child in childs: + product_ids = [x.id for x in child.product_ids] + stock_track.unlink(cr, uid, product_ids) + product_list = {} + for x in child.current_move_ids: + if x.location_dest_id.id == child.location_id.id: + if x.product_id.id not in product_list.keys(): + product_list.update({x.product_id.id:x.product_qty}) + else: + product_list[x.product_id.id] += x.product_qty + for product in product_list.keys(): + stock_track.create(cr, uid, {'product_id': product, 'quantity': product_list[product], 'tracking_id': child.id}) + return True + + def get_serials(self, cr, uid, ids, context=None): + pack_ids = self.browse(cr, uid, ids, context) + serial_track = self.pool.get('serial.stock.tracking') + serial_obj = self.pool.get('stock.production.lot') + for pack in pack_ids: + childs = self.hierarchy_ids(pack) + for child in childs: + serial_ids = [x.id for x in child.serial_ids] + serial_track.unlink(cr, uid, serial_ids) + serial_list = {} + for x in child.current_move_ids: + if x.location_dest_id.id == child.location_id.id: + if x.prodlot_id.id not in serial_list.keys(): + serial_list.update({x.prodlot_id.id:x.product_qty}) + else: + serial_list[x.prodlot_id.id] += x.product_qty + for serial in serial_list.keys(): + if serial: + serial_track.create(cr, uid, {'serial_id': serial, 'quantity': serial_list[serial], 'tracking_id': child.id}) + serial_obj.write(cr, uid, [serial], {'tracking_id': child.id}) + return True + +stock_tracking() + +class product_ul(osv.osv): + _inherit = "product.ul" + _description = "Shipping Unit" + _columns = { + 'capacity_index': fields.integer('Capacity index'), + } + _order = 'capacity_index' +product_ul() + +class product_stock_tracking(osv.osv): + + _name = 'product.stock.tracking' + + _columns = { + 'product_id': fields.many2one('product.product', 'Product'), + 'quantity': fields.float('Quantity'), + 'tracking_id': fields.many2one('stock.tracking', 'Tracking'), +# 'tracking_history_id': fields.many2one('stock.tracking.history', 'Tracking History'), + } + +product_stock_tracking() + +class serial_stock_tracking(osv.osv): + + _name = 'serial.stock.tracking' + + _order = 'tracking_id,serial_id' + + _columns = { + 'serial_id': fields.many2one('stock.production.lot', 'Serial'), + 'product_id': fields.related('serial_id', 'product_id', type='many2one', relation='product.product', string='Product'), + 'quantity': fields.float('Quantity'), + 'tracking_id': fields.many2one('stock.tracking', 'Tracking'), +# 'tracking_history_id': fields.many2one('stock.tracking.history', 'Tracking History'), + } + +serial_stock_tracking() + +class stock_tracking_history(osv.osv): + + _name = "stock.tracking.history" + + def _get_types(self, cr, uid, context={}): +# res = [('pack_in','Add parent'),('pack_out','Unlink parent'),('move','Move')] + res = [] + return res + +# def hierarchy_ids(self, tracking): +# result_list = [tracking] +# for child in tracking.child_ids: +# result_list.extend(self.hierarchy_ids(child)) +# return result_list +# +# def _get_child_products(self, cr, uid, ids, field_name, arg, context=None): +# packs = self.browse(cr, uid, ids) +# res = {} +# for pack in packs: +# res[pack.id] = [] +# childs = self.hierarchy_ids(pack) +# for child in childs: +# for prod in child.product_ids: +# res[pack.id].append(prod.id) +# return res + + _columns = { + 'tracking_id': fields.many2one('stock.tracking', 'Pack', required=True), + 'type': fields.selection(_get_types, 'Type'), +# 'product_ids': fields.one2many('product.stock.tracking', 'tracking_history_id', 'Products'), +# 'child_product_ids': fields.function(_get_child_products, method=True, type='one2many', obj='product.stock.tracking', string='Child Products'), +# 'parent_hist_id': fields.many2one('stock.tracking.history', 'Parent history pack'), +# 'child_ids': fields.one2many('stock.tracking.history', 'parent_hist_id', 'Child history pack'), + } + + _rec_name = "tracking_id" + +stock_tracking_history() + +'''Add a field in order to store the current pack in a production lot''' +class stock_production_lot(osv.osv): + _inherit = 'stock.production.lot' + _columns = { + 'tracking_id': fields.many2one('stock.tracking', 'pack'), + } + +stock_production_lot() + +class product_category(osv.osv): + _inherit = 'product.category' + _columns = { + 'tracked': fields.boolean('Need a serial code ?'), + } +product_category() + +class stock_inventory(osv.osv): + _inherit = 'stock.inventory' + _defaults = { + 'name': lambda x, y, z, c: x.pool.get('ir.sequence').get(y, z, 'stock.inventory') or '/' + } +stock_inventory() + +class stock_move(osv.osv): + _inherit = 'stock.move' + _columns = { +# 'cancel_cascade': fields.boolean('Cancel Cascade', help='If checked, when this move is cancelled, cancel the linked move too') + } + + def create(self, cr, uid, vals, context=None): + production_lot_obj = self.pool.get('stock.production.lot') + stock_tracking_obj = self.pool.get('stock.tracking') + if vals.get('prodlot_id',False): + production_lot_data = production_lot_obj.browse(cr, uid, vals['prodlot_id']) + last_production_lot_move_id = self.search(cr, uid, [('prodlot_id', '=', production_lot_data.id)], limit=1, order='date') + if last_production_lot_move_id: + last_production_lot_move = self.browse(cr,uid,last_production_lot_move_id[0]) + if last_production_lot_move.tracking_id: + ids = [last_production_lot_move.tracking_id.id] + stock_tracking_obj.reset_open(cr, uid, ids, context=None) + + return super(stock_move,self).create(cr, uid, vals, context) + +stock_move() +class split_in_production_lot(osv.osv_memory): + _inherit = "stock.move.split" + _columns = { + 'use_exist' : fields.boolean('Existing Lots', invisible=True), + } + _defaults = { + 'use_exist': lambda *a: True, + } + def default_get(self, cr, uid, fields, context=None): + res = super(split_in_production_lot, self).default_get(cr, uid, fields, context) + res.update({'use_exist': True}) + return res + +split_in_production_lot() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/stock_tracking_extended/stock_tracking_view.xml b/stock_tracking_extended/stock_tracking_view.xml new file mode 100644 index 000000000..cf66856f6 --- /dev/null +++ b/stock_tracking_extended/stock_tracking_view.xml @@ -0,0 +1,270 @@ + + + + + + + + product.category.property.form.inherit + product.category + form + + + + + + + + + + stock.tracking.tree.inherit + stock.tracking + tree + + + + + + + + + + + + + stock.tracking.tree.inherit + stock.tracking + tree + + + + + + + + + + + stock.tracking.form.inherit + stock.tracking + form + + + + + + + + + + + +
+ + + +