From 5509d77f56a70df5de23b1b2fe86dfb1a6cdd204 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Sun, 21 Jun 2015 01:24:41 -0300 Subject: [PATCH 001/123] [REF] Renaming module stock_invoice_picking -> stock_picking_invoicing --- stock_picking_invoicing/README.rst | 34 ++++++++++++ stock_picking_invoicing/__init__.py | 21 ++++++++ stock_picking_invoicing/__openerp__.py | 33 ++++++++++++ .../static/description/icon.png | Bin 0 -> 9455 bytes stock_picking_invoicing/stock.py | 51 ++++++++++++++++++ stock_picking_invoicing/stock_view.xml | 15 ++++++ 6 files changed, 154 insertions(+) create mode 100644 stock_picking_invoicing/README.rst create mode 100644 stock_picking_invoicing/__init__.py create mode 100644 stock_picking_invoicing/__openerp__.py create mode 100644 stock_picking_invoicing/static/description/icon.png create mode 100644 stock_picking_invoicing/stock.py create mode 100644 stock_picking_invoicing/stock_view.xml diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst new file mode 100644 index 00000000000..ea26222559b --- /dev/null +++ b/stock_picking_invoicing/README.rst @@ -0,0 +1,34 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License: AGPL-3 + +Stock invoice picking +===================== + +This module allows to create invoices directly from picking, without having to +use sale or purchase orders. + +Credits +======= + +Contributors +------------ + +* Lorenzo Battistini +* Leonardo Pistone +* Daniel Sadamo +* Alex Comba + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/stock_picking_invoicing/__init__.py b/stock_picking_invoicing/__init__.py new file mode 100644 index 00000000000..01458b47d0f --- /dev/null +++ b/stock_picking_invoicing/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013-15 Agile Business Group sagl () +# +# 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 . import stock diff --git a/stock_picking_invoicing/__openerp__.py b/stock_picking_invoicing/__openerp__.py new file mode 100644 index 00000000000..bfd44ab5ea0 --- /dev/null +++ b/stock_picking_invoicing/__openerp__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013-15 Agile Business Group sagl () +# +# 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 . +# +############################################################################## + +{ + 'name': "Stock Picking Invoicing", + 'version': '1.0', + 'category': 'Warehouse Management', + 'author': "Agile Business Group,Odoo Community Association (OCA)", + 'website': 'http://www.agilebg.com', + 'license': 'AGPL-3', + "depends": ['stock_picking_invoice_link'], + "data": [ + "stock_view.xml", + ], + "installable": True +} diff --git a/stock_picking_invoicing/static/description/icon.png b/stock_picking_invoicing/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/stock_picking_invoicing/stock.py b/stock_picking_invoicing/stock.py new file mode 100644 index 00000000000..9edf27324cb --- /dev/null +++ b/stock_picking_invoicing/stock.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013-15 Agile Business Group sagl () +# +# 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 openerp import models, api, _ +from openerp.exceptions import Warning + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + @api.model + def _get_partner_to_invoice(self, picking): + partner_obj = self.env['res.partner'] + partner = super(StockPicking, self)._get_partner_to_invoice(picking) + if isinstance(partner, int): + partner = partner_obj.browse(partner) + if picking.partner_id.id != partner.id: + # if someone else modified invoice partner, I use it + return partner.id + return partner.address_get( + ['invoice'])['invoice'] + + @api.multi + def set_to_be_invoiced(self): + for picking in self: + if picking.invoice_state == '2binvoiced': + raise Warning(_("Can't update invoice control for picking %s: " + "It's 'to be invoiced' yet") % picking.name) + if picking.invoice_state in ('none', 'invoiced'): + if picking.invoice_id: + raise Warning(_('Picking %s has linked invoice %s') % + (picking.name, picking.invoice_id.number)) + picking.invoice_state = '2binvoiced' + return True diff --git a/stock_picking_invoicing/stock_view.xml b/stock_picking_invoicing/stock_view.xml new file mode 100644 index 00000000000..6da355e55d9 --- /dev/null +++ b/stock_picking_invoicing/stock_view.xml @@ -0,0 +1,15 @@ + + + + + stock.picking.invoice.form + stock.picking + + + + + + + + From 1176fececa7dc81a6fc6667f1a9bc2e93747cad1 Mon Sep 17 00:00:00 2001 From: Alex Comba Date: Tue, 23 Jun 2015 12:27:33 +0200 Subject: [PATCH 002/123] Fix module name in README --- stock_picking_invoicing/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index ea26222559b..b538bec3f53 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -1,8 +1,8 @@ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg :alt: License: AGPL-3 -Stock invoice picking -===================== +Stock picking invoicing +======================= This module allows to create invoices directly from picking, without having to use sale or purchase orders. From fe12733e7323b3b030ab1ac826af79320f0c8fe6 Mon Sep 17 00:00:00 2001 From: Alex Comba Date: Tue, 23 Jun 2015 12:30:53 +0200 Subject: [PATCH 003/123] Add Bug Tracker to README --- stock_picking_invoicing/README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index b538bec3f53..45828922622 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -7,6 +7,14 @@ Stock picking invoicing This module allows to create invoices directly from picking, without having to use sale or purchase orders. +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed feedback +`here `_. + Credits ======= From af5188119e79dbefcb61c5efd01f5def9e9db723 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Tue, 23 Jun 2015 12:48:15 +0200 Subject: [PATCH 004/123] [FIX] stock_picking_invoicing: README --- stock_picking_invoicing/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index 45828922622..7baf7655ecd 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -13,7 +13,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed feedback -`here `_. +`here `_. Credits ======= From a6236bd78ae5291f1901edefc100ad4eb16a6c91 Mon Sep 17 00:00:00 2001 From: eLBati Date: Tue, 23 Jun 2015 14:59:55 +0200 Subject: [PATCH 005/123] [FIX] wrong bug tracker link --- stock_picking_invoicing/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index 7baf7655ecd..b81a529190a 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -10,7 +10,7 @@ use sale or purchase orders. Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. +Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed feedback `here `_. From 3cacf11f288c5c3777b44a9445787c5c8175e8b4 Mon Sep 17 00:00:00 2001 From: eLBati Date: Tue, 7 Jul 2015 17:20:29 +0200 Subject: [PATCH 006/123] [FIX] using wrong partner for invoice, when delivering to a company address --- stock_picking_invoicing/stock.py | 16 +++++ stock_picking_invoicing/tests/__init__.py | 21 ++++++ .../tests/test_picking_invoicing.py | 70 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 stock_picking_invoicing/tests/__init__.py create mode 100644 stock_picking_invoicing/tests/test_picking_invoicing.py diff --git a/stock_picking_invoicing/stock.py b/stock_picking_invoicing/stock.py index 9edf27324cb..b3cf9ac4e82 100644 --- a/stock_picking_invoicing/stock.py +++ b/stock_picking_invoicing/stock.py @@ -49,3 +49,19 @@ def set_to_be_invoiced(self): (picking.name, picking.invoice_id.number)) picking.invoice_state = '2binvoiced' return True + + +class StockMove(models.Model): + _inherit = 'stock.move' + + @api.model + def _get_master_data(self, move, company): + data = super(StockMove, self)._get_master_data(move, company) + if move.picking_id.partner_id.id != data[0].id: + # if someone else modified invoice partner, I use it + return data + partner_invoice_id = move.picking_id.partner_id.address_get( + ['invoice'])['invoice'] + partner = self.env['res.partner'].browse(partner_invoice_id) + new_data = partner, data[1], data[2] + return new_data diff --git a/stock_picking_invoicing/tests/__init__.py b/stock_picking_invoicing/tests/__init__.py new file mode 100644 index 00000000000..71ff1d347c1 --- /dev/null +++ b/stock_picking_invoicing/tests/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Lorenzo Battistini +# +# 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 . import test_picking_invoicing diff --git a/stock_picking_invoicing/tests/test_picking_invoicing.py b/stock_picking_invoicing/tests/test_picking_invoicing.py new file mode 100644 index 00000000000..49a2ca92c90 --- /dev/null +++ b/stock_picking_invoicing/tests/test_picking_invoicing.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Lorenzo Battistini +# +# 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 openerp.tests.common as test_common + + +class TestPickingInvoicing(test_common.SingleTransactionCase): + + def setUp(self): + super(TestPickingInvoicing, self).setUp() + self.picking_model = self.env['stock.picking'] + self.move_model = self.env['stock.move'] + self.invoice_wizard = self.env['stock.invoice.onshipping'] + self.invoice_model = self.env['account.invoice'] + self.partner_model = self.env['res.partner'] + + def test_0_picking_invoicing(self): + agrolait = self.partner_model.browse(self.ref('base.res_partner_2')) + # setting Agrolait type to default, because it's 'contact' in demo data + agrolait.write({'type': 'default'}) + picking = self.picking_model.create({ + # using Agrolait, Michel Fletcher + 'partner_id': self.ref('base.res_partner_address_4'), + 'picking_type_id': self.ref('stock.picking_type_in'), + }) + prod_id = self.ref('product.product_product_10') + move_vals = self.move_model.onchange_product_id( + prod_id=prod_id)['value'] + move_vals['product_id'] = prod_id + move_vals['picking_id'] = picking.id + move_vals['location_dest_id'] = self.ref( + 'stock.stock_location_customers') + move_vals['location_id'] = self.ref( + 'stock.stock_location_stock') + self.move_model.create(move_vals) + picking.set_to_be_invoiced() + picking.action_confirm() + picking.action_assign() + picking.do_prepare_partial() + picking.do_transfer() + self.assertEqual(picking.state, 'done') + wizard = self.invoice_wizard.with_context( + { + 'active_ids': [picking.id], + 'active_model': 'stock.picking', + 'active_id': picking.id, + } + ).create({'journal_id': self.ref('account.sales_journal')}) + invoices = wizard.create_invoice() + self.assertEqual(picking.invoice_state, 'invoiced') + invoice = self.invoice_model.browse(invoices[0]) + # invoice partner must be Agrolait + self.assertEqual(invoice.partner_id.id, self.ref('base.res_partner_2')) From 85ff5134e938dd30a2940c4a09372a5c84e6eb93 Mon Sep 17 00:00:00 2001 From: OCA Transbot Date: Tue, 1 Sep 2015 12:08:04 -0400 Subject: [PATCH 007/123] OCA Transbot updated translations from Transifex --- stock_picking_invoicing/i18n/en.po | 45 +++++++++++++++++++++++++++++ stock_picking_invoicing/i18n/sl.po | 46 ++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 stock_picking_invoicing/i18n/en.po create mode 100644 stock_picking_invoicing/i18n/sl.po diff --git a/stock_picking_invoicing/i18n/en.po b/stock_picking_invoicing/i18n/en.po new file mode 100644 index 00000000000..c2fbf914b89 --- /dev/null +++ b/stock_picking_invoicing/i18n/en.po @@ -0,0 +1,45 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_invoicing +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: account-invoicing (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-25 16:48+0000\n" +"PO-Revision-Date: 2015-08-14 15:31+0000\n" +"Last-Translator: OCA Transbot \n" +"Language-Team: English (http://www.transifex.com/oca/OCA-account-invoicing-8-0/language/en/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: en\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_picking_invoicing +#: code:addons/stock_picking_invoicing/stock.py:44 +#, python-format +msgid "Can't update invoice control for picking %s: It's 'to be invoiced' yet" +msgstr "Can't update invoice control for picking %s: It's 'to be invoiced' yet" + +#. module: stock_picking_invoicing +#: code:addons/stock_picking_invoicing/stock.py:48 +#, python-format +msgid "Picking %s has linked invoice %s" +msgstr "Picking %s has linked invoice %s" + +#. module: stock_picking_invoicing +#: model:ir.model,name:stock_picking_invoicing.model_stock_picking +msgid "Picking List" +msgstr "Picking List" + +#. module: stock_picking_invoicing +#: view:stock.picking:stock_picking_invoicing.stock_picking_invoice_out_form +msgid "Set to be invoiced" +msgstr "Set to be invoiced" + +#. module: stock_picking_invoicing +#: model:ir.model,name:stock_picking_invoicing.model_stock_move +msgid "Stock Move" +msgstr "Stock Move" diff --git a/stock_picking_invoicing/i18n/sl.po b/stock_picking_invoicing/i18n/sl.po new file mode 100644 index 00000000000..634982ad36a --- /dev/null +++ b/stock_picking_invoicing/i18n/sl.po @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_invoicing +# +# Translators: +# Matjaž Mozetič , 2015 +msgid "" +msgstr "" +"Project-Id-Version: account-invoicing (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-25 16:48+0000\n" +"PO-Revision-Date: 2015-08-16 11:38+0000\n" +"Last-Translator: Matjaž Mozetič \n" +"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-account-invoicing-8-0/language/sl/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: sl\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" + +#. module: stock_picking_invoicing +#: code:addons/stock_picking_invoicing/stock.py:44 +#, python-format +msgid "Can't update invoice control for picking %s: It's 'to be invoiced' yet" +msgstr "Nadzora obračuna za zbirnik %s ni mogoče posodobiti: ni še zaračunan" + +#. module: stock_picking_invoicing +#: code:addons/stock_picking_invoicing/stock.py:48 +#, python-format +msgid "Picking %s has linked invoice %s" +msgstr "Zbirnik %s je povezan z računom %s" + +#. module: stock_picking_invoicing +#: model:ir.model,name:stock_picking_invoicing.model_stock_picking +msgid "Picking List" +msgstr "Zbirni seznam" + +#. module: stock_picking_invoicing +#: view:stock.picking:stock_picking_invoicing.stock_picking_invoice_out_form +msgid "Set to be invoiced" +msgstr "Nastavljeno za obračun" + +#. module: stock_picking_invoicing +#: model:ir.model,name:stock_picking_invoicing.model_stock_move +msgid "Stock Move" +msgstr "Premik zaloge" From 965a0a507ab6813f79a67052c99c0d8741e65c46 Mon Sep 17 00:00:00 2001 From: OCA Transbot Date: Sat, 12 Sep 2015 20:02:42 -0400 Subject: [PATCH 008/123] OCA Transbot updated translations from Transifex --- stock_picking_invoicing/i18n/fr.po | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 stock_picking_invoicing/i18n/fr.po diff --git a/stock_picking_invoicing/i18n/fr.po b/stock_picking_invoicing/i18n/fr.po new file mode 100644 index 00000000000..64dadbde217 --- /dev/null +++ b/stock_picking_invoicing/i18n/fr.po @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_invoicing +# +# Translators: +# Maxime Chambreuil , 2015 +msgid "" +msgstr "" +"Project-Id-Version: account-invoicing (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-09-09 12:43+0000\n" +"PO-Revision-Date: 2015-09-12 22:41+0000\n" +"Last-Translator: Maxime Chambreuil \n" +"Language-Team: French (http://www.transifex.com/oca/OCA-account-invoicing-8-0/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_picking_invoicing +#: code:addons/stock_picking_invoicing/stock.py:44 +#, python-format +msgid "Can't update invoice control for picking %s: It's 'to be invoiced' yet" +msgstr "Ne peut mettre à jour le contrôle de facturation sur le colisage %s : il est déjà 'À facturer'" + +#. module: stock_picking_invoicing +#: code:addons/stock_picking_invoicing/stock.py:48 +#, python-format +msgid "Picking %s has linked invoice %s" +msgstr "Le colisage %s est lié avec la facture %s" + +#. module: stock_picking_invoicing +#: model:ir.model,name:stock_picking_invoicing.model_stock_picking +msgid "Picking List" +msgstr "Liste de colisage" + +#. module: stock_picking_invoicing +#: view:stock.picking:stock_picking_invoicing.stock_picking_invoice_out_form +msgid "Set to be invoiced" +msgstr "Mis à facturer" + +#. module: stock_picking_invoicing +#: model:ir.model,name:stock_picking_invoicing.model_stock_move +msgid "Stock Move" +msgstr "Mouvement de stock" From 0670c16e3e3397124b46eb0eea539fd15de7412b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Fri, 9 Oct 2015 09:59:30 +0200 Subject: [PATCH 009/123] [UPD] prefix versions with 8.0 --- stock_picking_invoicing/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock_picking_invoicing/__openerp__.py b/stock_picking_invoicing/__openerp__.py index bfd44ab5ea0..c9df7f97a08 100644 --- a/stock_picking_invoicing/__openerp__.py +++ b/stock_picking_invoicing/__openerp__.py @@ -20,7 +20,7 @@ { 'name': "Stock Picking Invoicing", - 'version': '1.0', + 'version': '8.0.1.0.0', 'category': 'Warehouse Management', 'author': "Agile Business Group,Odoo Community Association (OCA)", 'website': 'http://www.agilebg.com', From 630eaefb28d5ed767b28f75c597a6f1a93b1084e Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Wed, 14 Oct 2015 03:00:58 +0200 Subject: [PATCH 010/123] [MIG] Make modules uninstallable --- stock_picking_invoicing/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock_picking_invoicing/__openerp__.py b/stock_picking_invoicing/__openerp__.py index c9df7f97a08..7628fef3d51 100644 --- a/stock_picking_invoicing/__openerp__.py +++ b/stock_picking_invoicing/__openerp__.py @@ -29,5 +29,5 @@ "data": [ "stock_view.xml", ], - "installable": True + 'installable': False } From af3d6df46a17479ae187b25a72ccddde51a0af9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Mon, 15 Aug 2016 18:54:27 +0200 Subject: [PATCH 011/123] [FIX] remove en.po that was erroneously created by transbot --- stock_picking_invoicing/i18n/en.po | 45 ------------------------------ 1 file changed, 45 deletions(-) delete mode 100644 stock_picking_invoicing/i18n/en.po diff --git a/stock_picking_invoicing/i18n/en.po b/stock_picking_invoicing/i18n/en.po deleted file mode 100644 index c2fbf914b89..00000000000 --- a/stock_picking_invoicing/i18n/en.po +++ /dev/null @@ -1,45 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * stock_picking_invoicing -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: account-invoicing (8.0)\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-08-25 16:48+0000\n" -"PO-Revision-Date: 2015-08-14 15:31+0000\n" -"Last-Translator: OCA Transbot \n" -"Language-Team: English (http://www.transifex.com/oca/OCA-account-invoicing-8-0/language/en/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Language: en\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. module: stock_picking_invoicing -#: code:addons/stock_picking_invoicing/stock.py:44 -#, python-format -msgid "Can't update invoice control for picking %s: It's 'to be invoiced' yet" -msgstr "Can't update invoice control for picking %s: It's 'to be invoiced' yet" - -#. module: stock_picking_invoicing -#: code:addons/stock_picking_invoicing/stock.py:48 -#, python-format -msgid "Picking %s has linked invoice %s" -msgstr "Picking %s has linked invoice %s" - -#. module: stock_picking_invoicing -#: model:ir.model,name:stock_picking_invoicing.model_stock_picking -msgid "Picking List" -msgstr "Picking List" - -#. module: stock_picking_invoicing -#: view:stock.picking:stock_picking_invoicing.stock_picking_invoice_out_form -msgid "Set to be invoiced" -msgstr "Set to be invoiced" - -#. module: stock_picking_invoicing -#: model:ir.model,name:stock_picking_invoicing.model_stock_move -msgid "Stock Move" -msgstr "Stock Move" From 9831701ce17c644a8e197881c30eb1e0f014b613 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Thu, 6 Oct 2016 14:46:42 +0200 Subject: [PATCH 012/123] [MIG] Rename manifest files --- stock_picking_invoicing/{__openerp__.py => __manifest__.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename stock_picking_invoicing/{__openerp__.py => __manifest__.py} (100%) diff --git a/stock_picking_invoicing/__openerp__.py b/stock_picking_invoicing/__manifest__.py similarity index 100% rename from stock_picking_invoicing/__openerp__.py rename to stock_picking_invoicing/__manifest__.py From 1f8bd8f3cc8de43186a985f5495aab2850344bf4 Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sat, 19 Mar 2016 19:47:20 +0100 Subject: [PATCH 013/123] Initiate the migration --- stock_picking_invoicing/README.rst | 1 + stock_picking_invoicing/__init__.py | 3 ++- stock_picking_invoicing/__manifest__.py | 11 ++++++---- stock_picking_invoicing/models/__init__.py | 21 +++++++++++++++++++ stock_picking_invoicing/{ => models}/stock.py | 0 .../{ => views}/stock_view.xml | 0 6 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 stock_picking_invoicing/models/__init__.py rename stock_picking_invoicing/{ => models}/stock.py (100%) rename stock_picking_invoicing/{ => views}/stock_view.xml (100%) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index b81a529190a..425c081dc13 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -25,6 +25,7 @@ Contributors * Leonardo Pistone * Daniel Sadamo * Alex Comba +* Florent THOMAS Maintainer ---------- diff --git a/stock_picking_invoicing/__init__.py b/stock_picking_invoicing/__init__.py index 01458b47d0f..ad674e760f2 100644 --- a/stock_picking_invoicing/__init__.py +++ b/stock_picking_invoicing/__init__.py @@ -18,4 +18,5 @@ # ############################################################################## -from . import stock +from . import models +#from . import wizard diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index 7628fef3d51..c9e41e844ce 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -20,14 +20,17 @@ { 'name': "Stock Picking Invoicing", - 'version': '8.0.1.0.0', + 'version': '9.0.1.0.0', 'category': 'Warehouse Management', 'author': "Agile Business Group,Odoo Community Association (OCA)", 'website': 'http://www.agilebg.com', 'license': 'AGPL-3', - "depends": ['stock_picking_invoice_link'], + "depends": [ + #'stock_picking_invoice_link' + + ], "data": [ - "stock_view.xml", + "views/stock_view.xml", ], - 'installable': False + 'installable': True } diff --git a/stock_picking_invoicing/models/__init__.py b/stock_picking_invoicing/models/__init__.py new file mode 100644 index 00000000000..01458b47d0f --- /dev/null +++ b/stock_picking_invoicing/models/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013-15 Agile Business Group sagl () +# +# 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 . import stock diff --git a/stock_picking_invoicing/stock.py b/stock_picking_invoicing/models/stock.py similarity index 100% rename from stock_picking_invoicing/stock.py rename to stock_picking_invoicing/models/stock.py diff --git a/stock_picking_invoicing/stock_view.xml b/stock_picking_invoicing/views/stock_view.xml similarity index 100% rename from stock_picking_invoicing/stock_view.xml rename to stock_picking_invoicing/views/stock_view.xml From 5987ef7d3ad5d97dc2089a58b49cd0110c86406e Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sat, 19 Mar 2016 21:57:05 +0100 Subject: [PATCH 014/123] Add the fields on the object and views --- stock_picking_invoicing/__manifest__.py | 1 + stock_picking_invoicing/models/stock.py | 101 +++++++++++++++--- stock_picking_invoicing/views/stock_view.xml | 83 +++++++++++++- .../wizard/stock_invoice_onshipping_view.xml | 37 +++++++ 4 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index c9e41e844ce..e9e2c5208e1 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -27,6 +27,7 @@ 'license': 'AGPL-3', "depends": [ #'stock_picking_invoice_link' + "stock" ], "data": [ diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index b3cf9ac4e82..c4dc7170f09 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -18,13 +18,97 @@ # ############################################################################## -from openerp import models, api, _ +import logging +from openerp import models, api, fields, _ from openerp.exceptions import Warning +_logger = logging.getLogger(__name__) + +INVOICE_STATE = [ + ("invoiced", "Invoiced"), + ("2binvoiced", "To Be Invoiced"), + ("none", "Not Applicable") + ] + + + +class StockLocationPath(models.Model): + _inherit = "stock.location.path" + + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") + + + @api.v7 + def _prepare_push_apply(self, cr, uid, rule, move, context=None): + res = super(stock_location_path, self)._prepare_push_apply(cr, uid, rule, move, context=context) + res['invoice_state'] = rule.invoice_state or 'none' + return res + +#---------------------------------------------------------- +# Procurement Rule +#---------------------------------------------------------- +class ProcurementRule(models.Model): + _inherit = 'procurement.rule' + + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") + +#---------------------------------------------------------- +# Procurement Order +#---------------------------------------------------------- + + +class ProcurementOrder(models.Model): + _inherit = "procurement.order" + + + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") + + @api.v7 + def _run_move_create(self, cr, uid, procurement, context=None): + res = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context) + res.update({'invoice_state': procurement.rule_id.invoice_state or procurement.invoice_state or 'none'}) + return res + + + +#---------------------------------------------------------- +# Move +#---------------------------------------------------------- + +class stock_move(models.Model): + _inherit = "stock.move" + + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") + + @api.model + def _get_master_data(self, move, company): + data = super(StockMove, self)._get_master_data(move, company) + if move.picking_id.partner_id.id != data[0].id: + # if someone else modified invoice partner, I use it + return data + partner_invoice_id = move.picking_id.partner_id.address_get( + ['invoice'])['invoice'] + partner = self.env['res.partner'].browse(partner_invoice_id) + new_data = partner, data[1], data[2] + return new_data + + + +#---------------------------------------------------------- +# Picking +#---------------------------------------------------------- class StockPicking(models.Model): _inherit = "stock.picking" + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") + + @api.model def _get_partner_to_invoice(self, picking): partner_obj = self.env['res.partner'] @@ -50,18 +134,3 @@ def set_to_be_invoiced(self): picking.invoice_state = '2binvoiced' return True - -class StockMove(models.Model): - _inherit = 'stock.move' - - @api.model - def _get_master_data(self, move, company): - data = super(StockMove, self)._get_master_data(move, company) - if move.picking_id.partner_id.id != data[0].id: - # if someone else modified invoice partner, I use it - return data - partner_invoice_id = move.picking_id.partner_id.address_get( - ['invoice'])['invoice'] - partner = self.env['res.partner'].browse(partner_invoice_id) - new_data = partner, data[1], data[2] - return new_data diff --git a/stock_picking_invoicing/views/stock_view.xml b/stock_picking_invoicing/views/stock_view.xml index 6da355e55d9..8a3e9e4052b 100644 --- a/stock_picking_invoicing/views/stock_view.xml +++ b/stock_picking_invoicing/views/stock_view.xml @@ -1,6 +1,84 @@ - + + + + + + stock.picking.tree.inherit + stock.picking + + + + + + + + + + + + + stock.move.form.inherit + stock.move + + + + + + + + + stock.procurement.rule.inherit.form + procurement.rule + + + + + + + + + stock.location.path.inherit.form + stock.location.path + + + + + + + + + stock.move.form.invoice_state + stock.move + + + + + + + + + + + stock.picking.form.inherit + stock.picking + + + + + {'default_invoice_state': invoice_state, 'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'default_picking_type_id': picking_type_id,'default_picking_id': active_id} + + + + + + + + diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml b/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml new file mode 100644 index 00000000000..c7cb86651b4 --- /dev/null +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml @@ -0,0 +1,37 @@ + + + + + + Stock Invoice Onshipping + stock.invoice.onshipping + +
+

+ +

+ + + + + +
+
+
+
+
+ + +
+
From 645f62689adc8176396db2493ff8e0de2209062e Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sun, 20 Mar 2016 14:30:31 +0100 Subject: [PATCH 015/123] Implements the mechanics of views : * Loading * Onchanges Etc --- stock_picking_invoicing/__init__.py | 2 +- stock_picking_invoicing/__manifest__.py | 3 +- stock_picking_invoicing/models/stock.py | 88 ++++- stock_picking_invoicing/views/stock_view.xml | 93 ++--- stock_picking_invoicing/wizard/__init__.py | 21 ++ .../wizard/stock_invoice_onshipping.py | 340 ++++++++++++++++++ .../wizard/stock_invoice_onshipping_view.xml | 14 +- 7 files changed, 512 insertions(+), 49 deletions(-) create mode 100644 stock_picking_invoicing/wizard/__init__.py create mode 100644 stock_picking_invoicing/wizard/stock_invoice_onshipping.py diff --git a/stock_picking_invoicing/__init__.py b/stock_picking_invoicing/__init__.py index ad674e760f2..f293988b892 100644 --- a/stock_picking_invoicing/__init__.py +++ b/stock_picking_invoicing/__init__.py @@ -19,4 +19,4 @@ ############################################################################## from . import models -#from . import wizard +from . import wizard diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index e9e2c5208e1..5699c934a90 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -26,12 +26,13 @@ 'website': 'http://www.agilebg.com', 'license': 'AGPL-3', "depends": [ - #'stock_picking_invoice_link' "stock" ], "data": [ "views/stock_view.xml", + "wizard/stock_invoice_onshipping_view.xml", ], + 'installable': True } diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index c4dc7170f09..dd91ca681bf 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -82,7 +82,13 @@ class stock_move(models.Model): _inherit = "stock.move" invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status", default="none") + string="Invoice Status" + , default="none" + ) + + invoice_line_id = fields.Many2one('account.invoice.line', string='Invoice Line') + invoice_id = fields.Many2one('account.invoice', string='Invoice', + related='invoice_line_id.invoice_id') @api.model def _get_master_data(self, move, company): @@ -96,8 +102,54 @@ def _get_master_data(self, move, company): new_data = partner, data[1], data[2] return new_data + + #https://github.com/OCA/account-invoicing/blob/8.0/stock_picking_invoicing_unified/models/stock_move.py + @api.model + def _get_invoice_line_vals(self, move, partner, inv_type): + res = super(StockMove, self)._get_invoice_line_vals(move, partner, + inv_type) + # negative value on quantity + if ((inv_type == 'out_invoice' and + move.location_id.usage == 'customer') or + (inv_type == 'out_refund' and + move.location_dest_id.usage == 'customer') or + (inv_type == 'in_invoice' and + move.location_dest_id.usage == 'supplier') or + (inv_type == 'in_refund' and + move.location_id.usage == 'supplier')): + res['quantity'] *= -1 + return res + @api.multi + def _get_price_unit_invoice(self, inv_type): + """ Gets price unit for invoice + @param move_line: Stock move lines + @param type: Type of invoice + @return: The price unit for the move line + """ + #TODO : Implements unit price +# if context is None: +# context = {} +# if type in ('in_invoice', 'in_refund'): +# return move_line.price_unit +# else: +# # If partner given, search price in its sale pricelist +# if move_line.partner_id and move_line.partner_id.property_product_pricelist: +# pricelist_obj = self.pool.get("product.pricelist") +# pricelist = move_line.partner_id.property_product_pricelist.id +# price = pricelist_obj.price_get(cr, uid, [pricelist], +# move_line.product_id.id, move_line.product_uom_qty, move_line.partner_id.id, { +# 'uom': move_line.product_uom.id, +# 'date': move_line.date, +# })[pricelist] +# if price: +# return price +# +# result = move_line.product_id.lst_price + + return 123.3 + #---------------------------------------------------------- # Picking #---------------------------------------------------------- @@ -106,8 +158,11 @@ class StockPicking(models.Model): _inherit = "stock.picking" invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status", default="none") + string="Invoice Status" + , default="none" + ) + invoice_id = fields.Many2one('account.invoice', string='Invoice') @api.model def _get_partner_to_invoice(self, picking): @@ -131,6 +186,33 @@ def set_to_be_invoiced(self): if picking.invoice_id: raise Warning(_('Picking %s has linked invoice %s') % (picking.name, picking.invoice_id.number)) - picking.invoice_state = '2binvoiced' + picking.invoice_state = '2binvoiced' return True + + @api.v7 + def action_invoice_create(self, cr, uid, ids, journal_id, group=False, type='out_invoice', context=None): + """ Creates invoice based on the invoice state selected for picking. + @param journal_id: Id of journal + @param group: Whether to create a group invoice or not + @param type: Type invoice to be created + @return: Ids of created invoices for the pickings + """ + context = context or {} + todo = {} + for picking in self.browse(cr, uid, ids, context=context): + partner = self._get_partner_to_invoice(cr, uid, picking, dict(context, type=type)) + #grouping is based on the invoiced partner + if group: + key = partner + else: + key = picking.id + for move in picking.move_lines: + if move.invoice_state == '2binvoiced': + if (move.state != 'cancel') and not move.scrapped: + todo.setdefault(key, []) + todo[key].append(move) + invoices = [] + for moves in todo.values(): + invoices += self._invoice_create_line(cr, uid, moves, journal_id, type, context=context) + return invoices \ No newline at end of file diff --git a/stock_picking_invoicing/views/stock_view.xml b/stock_picking_invoicing/views/stock_view.xml index 8a3e9e4052b..14f97998b22 100644 --- a/stock_picking_invoicing/views/stock_view.xml +++ b/stock_picking_invoicing/views/stock_view.xml @@ -10,13 +10,60 @@ - + + + + stock.picking.form.inherit + stock.picking + + + + + + + + + + + stock.move.form.invoice_state + stock.move + + + + + + + + + stock.move.form.inherit @@ -45,50 +92,12 @@ + - - stock.move.form.invoice_state - stock.move - - - - - - - - - - - stock.picking.form.inherit - stock.picking - - - - - {'default_invoice_state': invoice_state, 'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'default_picking_type_id': picking_type_id,'default_picking_id': active_id} - - - - - - - + + diff --git a/stock_picking_invoicing/wizard/__init__.py b/stock_picking_invoicing/wizard/__init__.py new file mode 100644 index 00000000000..e1dfc5ca630 --- /dev/null +++ b/stock_picking_invoicing/wizard/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013-15 Agile Business Group sagl () +# +# 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 . import stock_invoice_onshipping diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py new file mode 100644 index 00000000000..3c6862062d9 --- /dev/null +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py @@ -0,0 +1,340 @@ +# -*- 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 logging +from openerp.tools.translate import _ +from openerp import models, fields, api +from openerp.tools import config + + +JOURNAL_TYPE_MAP = { + ('outgoing', 'customer'): ['sale'], + ('outgoing', 'supplier'): ['purchase_refund'], + ('outgoing', 'transit'): ['sale', 'purchase_refund'], + ('incoming', 'supplier'): ['purchase'], + ('incoming', 'customer'): ['sale_refund'], + ('incoming', 'transit'): ['purchase', 'sale_refund'], +} + + +JOURNAL_TYPE = [ + ('purchase_refund', 'Refund Purchase'), + ('purchase', 'Create Supplier Invoice'), + ('sale_refund', 'Refund Sale'), + ('sale', 'Create Customer Invoice') +] + +_logger = logging.getLogger(__name__) + +class StockInvoiceOnshipping(models.TransientModel): + _name = 'stock.invoice.onshipping' + _description = "Stock Invoice Onshipping" + + + + @api.model + def _default_journal(self, journal_type): + default_journal = self.env['account.journal'].search( + [('type', '=', journal_type)])[:1] + + _logger.debug("default_journal : %s " % default_journal) + + return default_journal + + @api.model + def _get_journal(self): + journal_obj = self.env['account.journal'] + journal_type = self._get_journal_type() + _logger.debug("JOURNAL TYPE %s" % journal_type) + journals = journal_obj.search([('type', '=', journal_type)]) + _logger.debug("Journals %s" % journals) + _logger.debug("Journals %s" % journals[0].id) + + result = journals and journals[0] + _logger.debug("Journals %s" % result) + + return journals[:1] + + @api.model + def _get_journal_type(self): + + context = self.env.context or {} + res_ids = context and context.get('active_ids', []) + pick_obj = self.env['stock.picking'] + pickings = pick_obj.search([('id', 'in', res_ids)]) + pick = pickings and pickings[0] + if not pick or not pick.move_lines: + return 'sale' + type = pick.picking_type_id.code + usage = pick.move_lines[0].location_id.usage if type == 'incoming' else pick.move_lines[0].location_dest_id.usage + + return JOURNAL_TYPE_MAP.get((type, usage), ['sale'])[0] + + #======================= + # FIELDS + #======================= + + journal_id = fields.Many2one(comodel_name='account.journal' + , string= 'Destination Journal' + , default = _get_journal + , required=False) + journal_type = fields.Selection(JOURNAL_TYPE , 'Journal Type', + default = _get_journal_type, readonly=True) + + group = fields.Boolean("Group by partner") + invoice_date = fields.Date('Invoice Date') + + sale_journal = fields.Many2one( + comodel_name='account.journal', string='Sale Journal', + domain="[('type', '=', 'sale')]", + default=lambda self: self._default_journal('sale')) + sale_refund_journal = fields.Many2one( + comodel_name='account.journal', string='Sale Refund Journal', + domain="[('type', '=', 'sale_refund')]", + default=lambda self: self._default_journal('sale_refund')) + purchase_journal = fields.Many2one( + comodel_name='account.journal', string='Purchase Journal', + domain="[('type', '=', 'purchase')]", + default=lambda self: self._default_journal('purchase')) + purchase_refund_journal = fields.Many2one( + comodel_name='account.journal', string="Purchase Refund Journal", + domain="[('type', '=', 'purchase_refund')]", + default=lambda self: self._default_journal('purchase_refund')) + show_sale_journal = fields.Boolean(string="Show Sale Journal") + show_sale_refund_journal = fields.Boolean( + string="Show Refund Sale Journal") + show_purchase_journal = fields.Boolean(string="Show Purchase Journal") + show_purchase_refund_journal = fields.Boolean( + string="Show Refund Purchase Journal") + + + @api.onchange('group') + def onchange_group(self): + self.ensure_one() + (sale_pickings, sale_refund_pickings, purchase_pickings, + purchase_refund_pickings) = self.get_split_pickings() + self.show_sale_journal = bool(sale_pickings) + self.show_sale_refund_journal = bool(sale_refund_pickings) + self.show_purchase_journal = bool(purchase_pickings) + self.show_purchase_refund_journal = bool(purchase_refund_pickings) + +# @api.onchange('journal_id') + def onchange_journal_id(self): + _logger.debug("ON CHANGE") + context = self.env.context or {} + domain = {} + value = {} + active_id = context.get('active_id') + if active_id: + picking = self.env['stock.picking'].search(active_id) + type = picking.picking_type_id.code + usage = picking.move_lines[0].location_id.usage if type == 'incoming' else picking.move_lines[0].location_dest_id.usage + journal_types = JOURNAL_TYPE_MAP.get((type, usage), ['sale', 'purchase', 'sale_refund', 'purchase_refund']) + domain['journal_id'] = [('type', 'in', journal_types)] + if self.journal_id: + journal = self.env['account.journal'].search(journal_id) + + value['journal_type'] = journal.type + + return {'value': value, 'domain': domain} + + +# @api.cr_uid_ids_context + + @api.model + def view_init(self, fields): + _logger.debug("VIEW init") + context = self.env.context or {} + + res = super(StockInvoiceOnshipping, self).view_init(fields) + pick_obj = self.env['stock.picking'] + count = 0 + active_ids = context.get('active_ids',[]) + for pick in pick_obj.search([('id', 'in', active_ids)]): + if pick.invoice_state != '2binvoiced': + count += 1 + if len(active_ids) == count: + raise osv.except_osv(_('Warning!'), _('None of these picking lists require invoicing.')) + return res + + @api.multi + def open_invoice(self): + _logger.debug("OPEN INVOICE") + self.ensure_one() + if context is None: + context = {} + + invoice_ids = self.create_invoice(cr, uid, ids, context=context) + if not invoice_ids: + raise osv.except_osv(_('Error!'), _('No invoice created!')) + + data = self.search([self[0].id]) + + action_model = False + action = {} + + journal2type = {'sale':'out_invoice', 'purchase':'in_invoice' , 'sale_refund':'out_refund', 'purchase_refund':'in_refund'} + inv_type = journal2type.get(data.journal_type) or 'out_invoice' + data_pool = self.env[ir.model.data] + if inv_type == "out_invoice": + action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree1') + elif inv_type == "in_invoice": + action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree2') + elif inv_type == "out_refund": + action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree3') + elif inv_type == "in_refund": + action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree4') + + if action_id: + action_pool = self.env['ir.actions.act_window'] + action = action_pool.search(action_id) + action['domain'] = "[('id','in', ["+','.join(map(str,invoice_ids))+"])]" + return action + return True + + @api.multi + def create_invoice(self): + self.ensure_one() + context = self.env.context or {} + picking_pool = self.env[stock.picking] +# data = self.search(ids[0], context=context) + journal2type = {'sale':'out_invoice', 'purchase':'in_invoice', 'sale_refund':'out_refund', 'purchase_refund':'in_refund'} + context['date_inv'] = self.invoice_date + acc_journal = self.env[account.journal] + inv_type = journal2type.get(self.journal_type) or 'out_invoice' + context['inv_type'] = inv_type + + active_ids = context.get('active_ids', []) + res = picking_pool.action_invoice_create(cr, uid, active_ids, + journal_id = data.journal_id.id, + group = data.group, + type = inv_type, + context=context) +# return res + + +# @api.multi +# def create_invoice(self): + if (config['test_enable'] and + not self.env.context.get('test_picking_invoicing_unified')): + return res + self.ensure_one() + res = [] + (sale_pickings, sale_refund_pickings, purchase_pickings, + purchase_refund_pickings) = self.get_split_pickings() + if sale_pickings: + pickings = sale_pickings.with_context( + date_inv=self.invoice_date, inv_type='out_invoice') + res += pickings.action_invoice_create( + journal_id=self.sale_journal.id, + group=self.group, type='out_invoice') + if sale_refund_pickings: + pickings = sale_refund_pickings.with_context( + date_inv=self.invoice_date, inv_type='out_refund') + res += pickings.action_invoice_create( + journal_id=self.sale_refund_journal.id, + group=self.group, type='out_refund') + if purchase_pickings: + pickings = purchase_pickings.with_context( + date_inv=self.invoice_date, inv_type='in_invoice') + res += pickings.action_invoice_create( + journal_id=self.purchase_journal.id, + group=self.group, type='in_invoice') + if purchase_refund_pickings: + pickings = purchase_refund_pickings.with_context( + date_inv=self.invoice_date, inv_type='in_refund') + res += pickings.action_invoice_create( + journal_id=self.purchase_refund_journal.id, group=self.group, + type='in_refund') + return res + + + @api.multi + def get_partner_sum(self, pickings, partner, inv_type, picking_type, + usage): + move_obj = self.env['stock.move'] + pickings = pickings.filtered(lambda x: x.picking_type_id.code == + picking_type and x.partner_id == partner) + if picking_type == 'outgoing': + moves = pickings.mapped('move_lines').filtered( + lambda x: x.location_dest_id.usage == usage) + else: + moves = pickings.mapped('move_lines').filtered( + lambda x: x.location_id.usage == usage) + return (sum([(m._get_price_unit_invoice( inv_type) * + m.product_uom_qty) for m in moves]), + moves.mapped('picking_id')) + + @api.multi + def get_split_pickings_grouped(self, pickings): + sale_pickings = self.env['stock.picking'] + sale_refund_pickings = self.env['stock.picking'] + purchase_pickings = self.env['stock.picking'] + purchase_refund_pickings = self.env['stock.picking'] + + for partner in pickings.mapped('partner_id'): + so_sum, so_pickings = self.get_partner_sum( + pickings, partner, 'out_invoice', 'outgoing', 'customer') + si_sum, si_pickings = self.get_partner_sum( + pickings, partner, 'out_invoice', 'incoming', 'customer') + if (so_sum - si_sum) >= 0: + sale_pickings |= (so_pickings | si_pickings) + else: + sale_refund_pickings |= (so_pickings | si_pickings) + pi_sum, pi_pickings = self.get_partner_sum( + pickings, partner, 'in_invoice', 'incoming', 'supplier') + po_sum, po_pickings = self.get_partner_sum( + pickings, partner, 'in_invoice', 'outgoing', 'supplier') + if (pi_sum - po_sum) >= 0: + purchase_pickings |= (pi_pickings | po_pickings) + else: + purchase_refund_pickings |= (pi_pickings | po_pickings) + return (sale_pickings, sale_refund_pickings, purchase_pickings, + purchase_refund_pickings) + + @api.multi + def get_split_pickings_nogrouped(self, pickings): + sale_pickings = pickings.filtered( + lambda x: x.picking_type_id.code == 'outgoing' and + x.move_lines[:1].location_dest_id.usage == 'customer') + # use [:1] instead of [0] to avoid a errors on empty pickings + sale_refund_pickings = pickings.filtered( + lambda x: x.picking_type_id.code == 'incoming' and + x.move_lines[:1].location_id.usage == 'customer') + purchase_pickings = pickings.filtered( + lambda x: x.picking_type_id.code == 'incoming' and + x.move_lines[:1].location_id.usage == 'supplier') + purchase_refund_pickings = pickings.filtered( + lambda x: x.picking_type_id.code == 'outgoing' and + x.move_lines[:1].location_dest_id.usage == 'supplier') + return (sale_pickings, sale_refund_pickings, purchase_pickings, + purchase_refund_pickings) + + @api.multi + def get_split_pickings(self): + picking_obj = self.env['stock.picking'] + pickings = picking_obj.browse(self.env.context.get('active_ids', [])) + if self.group: + return self.get_split_pickings_grouped(pickings) + else: + return self.get_split_pickings_nogrouped(pickings) + + \ No newline at end of file diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml b/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml index c7cb86651b4..35b13bb7e02 100644 --- a/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml @@ -11,7 +11,17 @@ - + + + + + + + + + @@ -32,6 +42,6 @@ view_mode="form" view_type="form" target="new" - id="action_stock_invoice_onshipping"/> + id="action_stock_invoice_onshipping"/> From ca91b1f872582cd2dfc8668a84eca9400e183995 Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sun, 20 Mar 2016 18:34:25 +0100 Subject: [PATCH 016/123] Views Improvements --- stock_picking_invoicing/views/stock_view.xml | 45 ++++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/stock_picking_invoicing/views/stock_view.xml b/stock_picking_invoicing/views/stock_view.xml index 14f97998b22..3452c40feb0 100644 --- a/stock_picking_invoicing/views/stock_view.xml +++ b/stock_picking_invoicing/views/stock_view.xml @@ -3,7 +3,7 @@ - + stock.picking.tree.inherit stock.picking @@ -14,10 +14,20 @@ + + + + stock.picking.search.inherit + stock.picking + + + + + - - - + + + stock.picking.form.inherit stock.picking @@ -31,9 +41,9 @@ - + @@ -44,7 +54,9 @@ + @@ -57,9 +69,14 @@ + + + @@ -72,9 +89,21 @@ + + + + + + + + stock.procurement.rule.inherit.form procurement.rule From 5e60652ff0c4f1fe055e5804d6eba1b527a3d6de Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sun, 20 Mar 2016 18:48:02 +0100 Subject: [PATCH 017/123] Business logic Ok : * Good Price with pricelist * Good Taxes * group works * Everything is filtered with company --- stock_picking_invoicing/__manifest__.py | 2 +- stock_picking_invoicing/models/stock.py | 383 ++++++++++++++---- .../wizard/stock_invoice_onshipping.py | 179 ++++---- 3 files changed, 394 insertions(+), 170 deletions(-) diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index 5699c934a90..0d0ae486292 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -30,8 +30,8 @@ ], "data": [ - "views/stock_view.xml", "wizard/stock_invoice_onshipping_view.xml", + "views/stock_view.xml", ], 'installable': True diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index dd91ca681bf..8eac871ee54 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -19,24 +19,27 @@ ############################################################################## import logging -from openerp import models, api, fields, _ +from openerp import _ +from openerp import api +from openerp import fields +from openerp import models from openerp.exceptions import Warning _logger = logging.getLogger(__name__) INVOICE_STATE = [ - ("invoiced", "Invoiced"), - ("2binvoiced", "To Be Invoiced"), - ("none", "Not Applicable") - ] + ("invoiced", "Invoiced"), + ("2binvoiced", "To Be Invoiced"), + ("none", "Not Applicable") + ] class StockLocationPath(models.Model): _inherit = "stock.location.path" - invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status", default="none") + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") @api.v7 @@ -51,8 +54,8 @@ def _prepare_push_apply(self, cr, uid, rule, move, context=None): class ProcurementRule(models.Model): _inherit = 'procurement.rule' - invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status", default="none") + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") #---------------------------------------------------------- # Procurement Order @@ -63,8 +66,8 @@ class ProcurementOrder(models.Model): _inherit = "procurement.order" - invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status", default="none") + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status", default="none") @api.v7 def _run_move_create(self, cr, uid, procurement, context=None): @@ -81,46 +84,117 @@ def _run_move_create(self, cr, uid, procurement, context=None): class stock_move(models.Model): _inherit = "stock.move" - invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status" - , default="none" - ) + #===================== + # FIELDS + #===================== + + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status" + , default="none" + ) invoice_line_id = fields.Many2one('account.invoice.line', string='Invoice Line') invoice_id = fields.Many2one('account.invoice', string='Invoice', - related='invoice_line_id.invoice_id') + related='invoice_line_id.invoice_id') + + + #===================== + # Business Logic + #===================== + + @api.model + def _create_invoice_line_from_vals(self, invoice_line_vals): + return self.env['account.invoice.line'].create(invoice_line_vals) @api.model - def _get_master_data(self, move, company): - data = super(StockMove, self)._get_master_data(move, company) + def _get_master_data(self, move, company): + ''' returns a tuple (browse_record(res.partner), ID(res.users), ID(res.currency)''' + currency = company.currency_id.id + partner = move.picking_id and move.picking_id.partner_id + if partner: + code = self.get_code_from_locs(move) + if partner.property_product_pricelist and code == 'outgoing': + currency = partner.property_product_pricelist.currency_id.id + data = partner, self.env.uid, currency + if move.picking_id.partner_id.id != data[0].id: # if someone else modified invoice partner, I use it return data + partner_invoice_id = move.picking_id.partner_id.address_get( - ['invoice'])['invoice'] + ['invoice'])['invoice'] partner = self.env['res.partner'].browse(partner_invoice_id) new_data = partner, data[1], data[2] return new_data + + @api.multi + def _get_taxes(self): + taxes_ids = self.product_id.taxes_id + my_taxes = taxes_ids.filtered(lambda r: r.company_id.id == self.company_id.id) + my_taxes = [t.id for t in my_taxes] + return my_taxes + @api.multi + def _get_invoice_line_vals(self, partner, inv_type): + self.ensure_one() + fp_obj = self.env['account.fiscal.position'] + context = self.env.context - #https://github.com/OCA/account-invoicing/blob/8.0/stock_picking_invoicing_unified/models/stock_move.py - @api.model - def _get_invoice_line_vals(self, move, partner, inv_type): - res = super(StockMove, self)._get_invoice_line_vals(move, partner, - inv_type) + # Get account_id + fp = fp_obj.browse(cr, uid, context.get('fp_id')) if context.get('fp_id') else False + name = False + if inv_type in ('out_invoice', 'out_refund'): + account_id = self.product_id.property_account_income_id.id + if not account_id: + account_id = self.product_id.categ_id.property_account_income_categ_id.id + if self.procurement_id and self.procurement_id.sale_line_id: + name = self.procurement_id.sale_line_id.name + else: + account_id = self.product_id.property_account_expense_id.id + if not account_id: + account_id = self.product_id.categ_id.property_account_expense_categ_id.id + fiscal_position = fp or partner.property_account_position_id + account_id = fiscal_position.map_account(account_id) + + # set UoS if it's a sale and the picking doesn't have one + uos_id = self.product_uom.id + quantity = self.product_uom_qty +# if move.product_uos: +# uos_id = move.product_uos.id +# quantity = move.product_uos_qty + + + taxes_ids = self._get_taxes() + + res = { + 'name': name or self.name, + 'account_id': account_id, + 'product_id': self.product_id.id, + 'uos_id': uos_id, + 'quantity': quantity, + 'price_unit': self._get_price_unit_invoice(inv_type), + 'invoice_line_tax_ids': [(6, 0, taxes_ids)], + 'discount': 0.0, + 'account_analytic_id': False, + } + + #https://github.com/OCA/account-invoicing/blob/8.0/stock_picking_invoicing_unified/models/stock_move.py + + # negative value on quantity if ((inv_type == 'out_invoice' and - move.location_id.usage == 'customer') or - (inv_type == 'out_refund' and - move.location_dest_id.usage == 'customer') or - (inv_type == 'in_invoice' and - move.location_dest_id.usage == 'supplier') or - (inv_type == 'in_refund' and - move.location_id.usage == 'supplier')): + self.location_id.usage == 'customer') or + (inv_type == 'out_refund' and + self.location_dest_id.usage == 'customer') or + (inv_type == 'in_invoice' and + self.location_dest_id.usage == 'supplier') or + (inv_type == 'in_refund' and + self.location_id.usage == 'supplier')): res['quantity'] *= -1 - return res - + return res + + @api.multi def _get_price_unit_invoice(self, inv_type): """ Gets price unit for invoice @@ -128,27 +202,38 @@ def _get_price_unit_invoice(self, inv_type): @param type: Type of invoice @return: The price unit for the move line """ - #TODO : Implements unit price -# if context is None: -# context = {} -# if type in ('in_invoice', 'in_refund'): -# return move_line.price_unit -# else: -# # If partner given, search price in its sale pricelist -# if move_line.partner_id and move_line.partner_id.property_product_pricelist: -# pricelist_obj = self.pool.get("product.pricelist") -# pricelist = move_line.partner_id.property_product_pricelist.id -# price = pricelist_obj.price_get(cr, uid, [pricelist], -# move_line.product_id.id, move_line.product_uom_qty, move_line.partner_id.id, { -# 'uom': move_line.product_uom.id, -# 'date': move_line.date, -# })[pricelist] -# if price: -# return price -# -# result = move_line.product_id.lst_price - - return 123.3 + + if type in ('in_invoice', 'in_refund'): + return move_line.product_id.price + else: + # If partner given, search price in its sale pricelist + if self.partner_id and self.partner_id.property_product_pricelist: + self = self.with_context( + partner=self.partner_id.id, + quantity=self.product_uom_qty, + date=self.date, + pricelist=self.partner_id.property_product_pricelist.id, + uom=self.product_uom.id + ) + result = self.product_id.price + + return result + + @api.multi + def _get_moves_taxes(self, moves, inv_type): + + #extra moves with the same picking_id and product_id of a move have the same taxes + extra_move_tax = {} + is_extra_move = {} + for move in moves: + if move.picking_id: + is_extra_move[move.id] = True + if not (move.picking_id, move.product_id) in extra_move_tax: + extra_move_tax[move.picking_id, move.product_id] = 0 + else: + is_extra_move[move.id] = False + return (is_extra_move, extra_move_tax) + #---------------------------------------------------------- # Picking @@ -157,56 +242,193 @@ def _get_price_unit_invoice(self, inv_type): class StockPicking(models.Model): _inherit = "stock.picking" - invoice_state = fields.Selection(INVOICE_STATE, - string="Invoice Status" - , default="none" - ) - - invoice_id = fields.Many2one('account.invoice', string='Invoice') + #=========================== + # Views + #=========================== - @api.model - def _get_partner_to_invoice(self, picking): - partner_obj = self.env['res.partner'] - partner = super(StockPicking, self)._get_partner_to_invoice(picking) - if isinstance(partner, int): - partner = partner_obj.browse(partner) - if picking.partner_id.id != partner.id: - # if someone else modified invoice partner, I use it - return partner.id - return partner.address_get( - ['invoice'])['invoice'] - @api.multi def set_to_be_invoiced(self): for picking in self: if picking.invoice_state == '2binvoiced': raise Warning(_("Can't update invoice control for picking %s: " - "It's 'to be invoiced' yet") % picking.name) + "It's 'to be invoiced' yet") % picking.name) if picking.invoice_state in ('none', 'invoiced'): if picking.invoice_id: raise Warning(_('Picking %s has linked invoice %s') % (picking.name, picking.invoice_id.number)) picking.invoice_state = '2binvoiced' + for move in picking.move_lines: + if move.invoice_state != 'invoiced': + move.invoice_state = '2binvoiced' + return True + + @api.multi + def set_invoiced(self): + for picking in self: + if picking.invoice_state == 'invoiced' or picking.invoice_id : + raise Warning(_("Can't update invoice control for picking %s: " + "It's already invoiced!") % picking.name) + if picking.invoice_state in ('2binvoiced'): + if picking.invoice_id: + raise Warning(_('Picking %s has linked invoice %s') % + (picking.name, picking.invoice_id.number)) + picking.invoice_state = '2binvoiced' + for move in picking.move_lines: + if move.invoice_state != 'invoiced': + move.invoice_state = '2binvoiced' return True + #===================== + # FIELDS + #===================== + + invoice_state = fields.Selection(INVOICE_STATE, + string="Invoice Status" + , default="none" + ) - @api.v7 - def action_invoice_create(self, cr, uid, ids, journal_id, group=False, type='out_invoice', context=None): + invoice_id = fields.Many2one('account.invoice', string='Invoice') + + + #===================== + # Business Logic + #===================== + + @api.multi + def _create_invoice_from_picking(self, picking, vals): + ''' This function simply creates the invoice from the given values. It is overriden in delivery module to add the delivery costs. + ''' + invoice_obj = self.env['account.invoice'] + return invoice_obj.create(vals) + + @api.model + def _get_partner_to_invoice(self): + partner_obj = self.env['res.partner'] + + partner = self.partner_id + + return partner.address_get(['invoice'])['invoice'] + + @api.multi + def _get_invoice_vals(self, key, inv_type, journal_id, move): + partner, currency_id, company_id, user_id = key + if inv_type in ('out_invoice', 'out_refund'): + account_id = partner.property_account_receivable_id.id + payment_term = partner.property_payment_term_id.id or False + else: + account_id = partner.property_account_payable_id.id + payment_term = partner.property_supplier_payment_term_id.id or False + return { + 'origin': move.picking_id.name, + 'date_invoice': self.env.context.get('date_inv', False), + 'user_id': user_id, + 'partner_id': partner.id, + 'account_id': account_id, + 'payment_term_id': payment_term, + 'type': inv_type, + 'fiscal_position_id': partner.property_account_position_id.id, + 'company_id': company_id, + 'currency_id': currency_id, + 'journal_id': journal_id, + } + + + @api.model + def _invoice_create_line(self, moves, journal_id, inv_type='out_invoice'): + """ + Create an invoice and associated lines + """ + invoice_obj = self.env['account.invoice'] + move_obj = self.env['stock.move'] + invoices = {} + + is_extra_move, extra_move_tax = move_obj._get_moves_taxes(moves, inv_type) + product_price_unit = {} + + for move in moves: + company = move.company_id + origin = move.picking_id.name + partner, user_id, currency_id = move_obj._get_master_data(move, company) + key = (partner, currency_id, company.id, user_id) + + invoice_vals = self._get_invoice_vals(key, inv_type, journal_id, move) + if key not in invoices: + # Get account and payment terms + invoice_id = self._create_invoice_from_picking(move.picking_id, invoice_vals) + invoices[key] = invoice_id.id + + else: + invoice = invoice_obj.search([('id', '=', invoices[key])]) + merge_vals = {} + if not invoice.origin or invoice_vals['origin'] not in invoice.origin.split(', '): + invoice_origin = filter(None, [invoice.origin, invoice_vals['origin']]) + merge_vals['origin'] = ', '.join(invoice_origin) + + if invoice_vals.get('name', False) and (not invoice.name or invoice_vals['name'] not in invoice.name.split(', ')): + invoice_name = filter(None, [invoice.name, invoice_vals['name']]) + merge_vals['name'] = ', '.join(invoice_name) + if merge_vals: + invoice.write(merge_vals) + + move.with_context( + fp_id=invoice_vals.get('fiscal_position_id', False) + ) + + invoice_line_vals = move._get_invoice_line_vals(partner, inv_type) + invoice_line_vals['invoice_id'] = invoices[key] + invoice_line_vals['origin'] = origin + if not is_extra_move[move.id]: + product_price_unit[invoice_line_vals['product_id'], invoice_line_vals['uos_id']] = invoice_line_vals['price_unit'] + if is_extra_move[move.id] and (invoice_line_vals['product_id'], invoice_line_vals['uos_id']) in product_price_unit: + invoice_line_vals['price_unit'] = product_price_unit[invoice_line_vals['product_id'], invoice_line_vals['uos_id']] + if is_extra_move[move.id]: + desc = (inv_type in ('out_invoice', 'out_refund') and move.product_id.product_tmpl_id.description_sale) or \ + (inv_type in ('in_invoice', 'in_refund') and move.product_id.product_tmpl_id.description_purchase) + invoice_line_vals['name'] += ' ' + desc if desc else '' + if extra_move_tax[move.picking_id, move.product_id]: + invoice_line_vals['invoice_line_tax_id'] = extra_move_tax[move.picking_id, move.product_id] + #the default product taxes + elif (0, move.product_id) in extra_move_tax: + invoice_line_vals['invoice_line_tax_id'] = extra_move_tax[0, move.product_id] + + invoice_line = move._create_invoice_line_from_vals(invoice_line_vals) + if invoice_line : + move.write({'invoice_line_id': invoice_line.id, + 'invoice_state': 'invoiced' + }) + if move.picking_id and not move.picking_id.invoice_id : + move.picking_id.write({'invoice_id': invoice_id.id, + 'invoice_state': 'invoiced' + }) + + +# invoice_obj.button_compute(cr, uid, invoices.values(), context=context, set_total=(inv_type in ('in_invoice', 'in_refund'))) +# + + return invoices.values() + + + + @api.model + def action_invoice_create(self, ids, journal_id, group=False, type='out_invoice', context=None): """ Creates invoice based on the invoice state selected for picking. @param journal_id: Id of journal @param group: Whether to create a group invoice or not @param type: Type invoice to be created @return: Ids of created invoices for the pickings """ - context = context or {} + todo = {} - for picking in self.browse(cr, uid, ids, context=context): - partner = self._get_partner_to_invoice(cr, uid, picking, dict(context, type=type)) + + pickings = self.search([('id', 'in', ids)]) + for picking in pickings: + partner = self._get_partner_to_invoice() #grouping is based on the invoiced partner if group: key = partner else: key = picking.id + for move in picking.move_lines: if move.invoice_state == '2binvoiced': if (move.state != 'cancel') and not move.scrapped: @@ -214,5 +436,8 @@ def action_invoice_create(self, cr, uid, ids, journal_id, group=False, type='out todo[key].append(move) invoices = [] for moves in todo.values(): - invoices += self._invoice_create_line(cr, uid, moves, journal_id, type, context=context) + invoices += self._invoice_create_line(moves, journal_id, type) + + + return invoices \ No newline at end of file diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py index 3c6862062d9..038a95c927a 100644 --- a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py @@ -22,6 +22,7 @@ import logging from openerp.tools.translate import _ from openerp import models, fields, api +from openerp.exceptions import Warning from openerp.tools import config @@ -49,28 +50,79 @@ class StockInvoiceOnshipping(models.TransientModel): _description = "Stock Invoice Onshipping" + #================== + # View Parts + #================== @api.model - def _default_journal(self, journal_type): - default_journal = self.env['account.journal'].search( - [('type', '=', journal_type)])[:1] + def view_init(self, fields): + _logger.debug("VIEW init") + context = self.env.context or {} + + res = super(StockInvoiceOnshipping, self).view_init(fields) + pick_obj = self.env['stock.picking'] + count = 0 + active_ids = context.get('active_ids',[]) + for pick in pick_obj.search([('id', 'in', active_ids)]): + if pick.invoice_state != '2binvoiced': + count += 1 + if not pick.partner_id : + raise Warning(_('All your picking must have a partner to be invoiced!')) + if len(active_ids) == count: + _logger.debug("Raise ") + raise Warning(_('None of these picking lists require invoicing.')) - _logger.debug("default_journal : %s " % default_journal) + _logger.debug("RESULT %s") + + return res + + + @api.onchange('group') + def onchange_group(self): + self.ensure_one() + (sale_pickings, sale_refund_pickings, purchase_pickings, + purchase_refund_pickings) = self.get_split_pickings() + self.show_sale_journal = bool(sale_pickings) + self.show_sale_refund_journal = bool(sale_refund_pickings) + self.show_purchase_journal = bool(purchase_pickings) + self.show_purchase_refund_journal = bool(purchase_refund_pickings) + +# @api.onchange('journal_id') +# def onchange_journal_id(self): +# _logger.debug("ON CHANGE") +# context = self.env.context or {} +# domain = {} +# value = {} +# active_id = context.get('active_id') +# if active_id: +# picking = self.env['stock.picking'].search(active_id) +# type = picking.picking_type_id.code +# usage = picking.move_lines[0].location_id.usage if type == 'incoming' else picking.move_lines[0].location_dest_id.usage +# journal_types = JOURNAL_TYPE_MAP.get((type, usage), ['sale', 'purchase', 'sale_refund', 'purchase_refund']) +# domain['journal_id'] = [('type', 'in', journal_types)] +# if self.journal_id: +# journal = self.env['account.journal'].search(journal_id) +# +# value['journal_type'] = journal.type +# +# return {'value': value, 'domain': domain} + + + + @api.model + def _default_journal(self, journal_type): + company_id = self.env['res.users']._get_company() + default_journal = self.env['account.journal'].search( + [('type', '=', journal_type),('company_id','=', company_id )])[:1] return default_journal @api.model def _get_journal(self): journal_obj = self.env['account.journal'] journal_type = self._get_journal_type() - _logger.debug("JOURNAL TYPE %s" % journal_type) - journals = journal_obj.search([('type', '=', journal_type)]) - _logger.debug("Journals %s" % journals) - _logger.debug("Journals %s" % journals[0].id) - - result = journals and journals[0] - _logger.debug("Journals %s" % result) - + company_id = self.env['res.users']._get_company() + journals = journal_obj.search([('type', '=', journal_type),('company_id','=', company_id)]) return journals[:1] @api.model @@ -126,87 +178,35 @@ def _get_journal_type(self): string="Show Refund Purchase Journal") - @api.onchange('group') - def onchange_group(self): - self.ensure_one() - (sale_pickings, sale_refund_pickings, purchase_pickings, - purchase_refund_pickings) = self.get_split_pickings() - self.show_sale_journal = bool(sale_pickings) - self.show_sale_refund_journal = bool(sale_refund_pickings) - self.show_purchase_journal = bool(purchase_pickings) - self.show_purchase_refund_journal = bool(purchase_refund_pickings) - -# @api.onchange('journal_id') - def onchange_journal_id(self): - _logger.debug("ON CHANGE") - context = self.env.context or {} - domain = {} - value = {} - active_id = context.get('active_id') - if active_id: - picking = self.env['stock.picking'].search(active_id) - type = picking.picking_type_id.code - usage = picking.move_lines[0].location_id.usage if type == 'incoming' else picking.move_lines[0].location_dest_id.usage - journal_types = JOURNAL_TYPE_MAP.get((type, usage), ['sale', 'purchase', 'sale_refund', 'purchase_refund']) - domain['journal_id'] = [('type', 'in', journal_types)] - if self.journal_id: - journal = self.env['account.journal'].search(journal_id) - - value['journal_type'] = journal.type - - return {'value': value, 'domain': domain} - - -# @api.cr_uid_ids_context - - @api.model - def view_init(self, fields): - _logger.debug("VIEW init") - context = self.env.context or {} - - res = super(StockInvoiceOnshipping, self).view_init(fields) - pick_obj = self.env['stock.picking'] - count = 0 - active_ids = context.get('active_ids',[]) - for pick in pick_obj.search([('id', 'in', active_ids)]): - if pick.invoice_state != '2binvoiced': - count += 1 - if len(active_ids) == count: - raise osv.except_osv(_('Warning!'), _('None of these picking lists require invoicing.')) - return res + #================= + # Business part + #================= @api.multi def open_invoice(self): - _logger.debug("OPEN INVOICE") self.ensure_one() - if context is None: - context = {} - invoice_ids = self.create_invoice(cr, uid, ids, context=context) + invoice_ids = self.create_invoice() if not invoice_ids: - raise osv.except_osv(_('Error!'), _('No invoice created!')) + raise Warning(_('No invoice created!')) - data = self.search([self[0].id]) + data = self.search([('id', 'in', [self[0].id])]) action_model = False action = {} journal2type = {'sale':'out_invoice', 'purchase':'in_invoice' , 'sale_refund':'out_refund', 'purchase_refund':'in_refund'} inv_type = journal2type.get(data.journal_type) or 'out_invoice' - data_pool = self.env[ir.model.data] - if inv_type == "out_invoice": - action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree1') + data_pool = self.env['ir.actions.act_window'] + + if inv_type in ["out_invoice", "out_refund"]: + action_id = data_pool.for_xml_id('account','action_invoice_tree1') elif inv_type == "in_invoice": - action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree2') - elif inv_type == "out_refund": - action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree3') - elif inv_type == "in_refund": - action_id = data_pool.xmlid_to_res_id('account.action_invoice_tree4') + action_id = data_pool.for_xml_id('account','action_invoice_tree2') if action_id: - action_pool = self.env['ir.actions.act_window'] - action = action_pool.search(action_id) - action['domain'] = "[('id','in', ["+','.join(map(str,invoice_ids))+"])]" + action = action_id.copy() + action['domain'] = [('id','in', invoice_ids)] return action return True @@ -214,25 +214,24 @@ def open_invoice(self): def create_invoice(self): self.ensure_one() context = self.env.context or {} - picking_pool = self.env[stock.picking] -# data = self.search(ids[0], context=context) + picking_pool = self.env['stock.picking'] journal2type = {'sale':'out_invoice', 'purchase':'in_invoice', 'sale_refund':'out_refund', 'purchase_refund':'in_refund'} - context['date_inv'] = self.invoice_date - acc_journal = self.env[account.journal] + inv_type = journal2type.get(self.journal_type) or 'out_invoice' - context['inv_type'] = inv_type + active_ids = context.get('active_ids', []) - res = picking_pool.action_invoice_create(cr, uid, active_ids, - journal_id = data.journal_id.id, - group = data.group, - type = inv_type, - context=context) -# return res + self = self.with_context( + date_inv = self.invoice_date, + inv_type = inv_type + ) + res = picking_pool.action_invoice_create(active_ids, + journal_id = self.journal_id.id, + group = self.group, + type = inv_type) + return res -# @api.multi -# def create_invoice(self): if (config['test_enable'] and not self.env.context.get('test_picking_invoicing_unified')): return res From 1007a3ae4e825ed0a9c181ce2c2f6f74aba19d66 Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sun, 20 Mar 2016 19:23:15 +0100 Subject: [PATCH 018/123] Finalise business part : * Get the correct taxes and account regarding Fiscal Position --- stock_picking_invoicing/models/__init__.py | 1 + stock_picking_invoicing/models/invoice.py | 51 ++++++++++++++++++++++ stock_picking_invoicing/models/stock.py | 27 +++++++++--- 3 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 stock_picking_invoicing/models/invoice.py diff --git a/stock_picking_invoicing/models/__init__.py b/stock_picking_invoicing/models/__init__.py index 01458b47d0f..06168ef5713 100644 --- a/stock_picking_invoicing/models/__init__.py +++ b/stock_picking_invoicing/models/__init__.py @@ -19,3 +19,4 @@ ############################################################################## from . import stock +from . import invoice diff --git a/stock_picking_invoicing/models/invoice.py b/stock_picking_invoicing/models/invoice.py new file mode 100644 index 00000000000..85320954329 --- /dev/null +++ b/stock_picking_invoicing/models/invoice.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2013-15 Agile Business Group sagl () +# +# 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 logging +from openerp import _ +from openerp import api +from openerp import fields +from openerp import models +from openerp.exceptions import Warning + +_logger = logging.getLogger(__name__) + +INVOICE_STATE = [ + ("invoiced", "Invoiced"), + ("2binvoiced", "To Be Invoiced"), + ("none", "Not Applicable") + ] + +class AccountInvoice(models.Model): + _inherit = "account.invoice" + + @api.multi + def compute_invoice_tax_lines(self): + self.ensure_one() + taxes_grouped = self.get_taxes_values() + tax_lines = self.tax_line_ids.browse([]) + for tax in taxes_grouped.values(): + tax_lines += tax_lines.new(tax) + + self.tax_line_ids = tax_lines + + return [] + + \ No newline at end of file diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index 8eac871ee54..391f85249e7 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -34,7 +34,6 @@ ] - class StockLocationPath(models.Model): _inherit = "stock.location.path" @@ -128,11 +127,22 @@ def _get_master_data(self, move, company): return new_data @api.multi - def _get_taxes(self): + def _get_taxes(self, fiscal_position): + self.ensure_one() taxes_ids = self.product_id.taxes_id my_taxes = taxes_ids.filtered(lambda r: r.company_id.id == self.company_id.id) + my_taxes = fiscal_position.map_tax(my_taxes) my_taxes = [t.id for t in my_taxes] + _logger.debug("TAXES %s" % my_taxes) + return my_taxes + + @api.multi + def _get_account(self, fiscal_position, account_id): + self.ensure_one() + account_id = fiscal_position.map_account(account_id) + + return account_id @api.multi def _get_invoice_line_vals(self, partner, inv_type): @@ -154,7 +164,8 @@ def _get_invoice_line_vals(self, partner, inv_type): if not account_id: account_id = self.product_id.categ_id.property_account_expense_categ_id.id fiscal_position = fp or partner.property_account_position_id - account_id = fiscal_position.map_account(account_id) + + account_id = self._get_account(fiscal_position, account_id) # set UoS if it's a sale and the picking doesn't have one uos_id = self.product_uom.id @@ -164,13 +175,14 @@ def _get_invoice_line_vals(self, partner, inv_type): # quantity = move.product_uos_qty - taxes_ids = self._get_taxes() + taxes_ids = self._get_taxes(fiscal_position) res = { - 'name': name or self.name, + 'name': name or (self.picking_id.name + '\n' + self.name), 'account_id': account_id, 'product_id': self.product_id.id, 'uos_id': uos_id, + 'uom_id': uos_id, 'quantity': quantity, 'price_unit': self._get_price_unit_invoice(inv_type), 'invoice_line_tax_ids': [(6, 0, taxes_ids)], @@ -215,7 +227,7 @@ def _get_price_unit_invoice(self, inv_type): pricelist=self.partner_id.property_product_pricelist.id, uom=self.product_uom.id ) - result = self.product_id.price + result = self.product_id.price return result @@ -345,6 +357,7 @@ def _invoice_create_line(self, moves, journal_id, inv_type='out_invoice'): is_extra_move, extra_move_tax = move_obj._get_moves_taxes(moves, inv_type) product_price_unit = {} + invoice_id = None for move in moves: company = move.company_id origin = move.picking_id.name @@ -401,6 +414,8 @@ def _invoice_create_line(self, moves, journal_id, inv_type='out_invoice'): 'invoice_state': 'invoiced' }) + + invoice_id.compute_invoice_tax_lines() # invoice_obj.button_compute(cr, uid, invoices.values(), context=context, set_total=(inv_type in ('in_invoice', 'in_refund'))) # From 751fc6cbf7f018502c050384a07dbd9fb1daa070 Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Sun, 20 Mar 2016 21:16:41 +0100 Subject: [PATCH 019/123] Correction of bad Class usage --- stock_picking_invoicing/models/stock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index 391f85249e7..f00b16ba02b 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -43,7 +43,7 @@ class StockLocationPath(models.Model): @api.v7 def _prepare_push_apply(self, cr, uid, rule, move, context=None): - res = super(stock_location_path, self)._prepare_push_apply(cr, uid, rule, move, context=context) + res = super(StockLocationPath, self)._prepare_push_apply(cr, uid, rule, move, context=context) res['invoice_state'] = rule.invoice_state or 'none' return res @@ -70,7 +70,7 @@ class ProcurementOrder(models.Model): @api.v7 def _run_move_create(self, cr, uid, procurement, context=None): - res = super(procurement_order, self)._run_move_create(cr, uid, procurement, context=context) + res = super(ProcurementOrder, self)._run_move_create(cr, uid, procurement, context=context) res.update({'invoice_state': procurement.rule_id.invoice_state or procurement.invoice_state or 'none'}) return res From 7eefab45d5397dcbb4f2d66b1f1ed7a13fd27af3 Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Mon, 21 Mar 2016 01:56:29 +0100 Subject: [PATCH 020/123] Add intercompany workflow --- stock_picking_invoicing/models/invoice.py | 5 ----- stock_picking_invoicing/models/stock.py | 1 - 2 files changed, 6 deletions(-) diff --git a/stock_picking_invoicing/models/invoice.py b/stock_picking_invoicing/models/invoice.py index 85320954329..39fd59bbde2 100644 --- a/stock_picking_invoicing/models/invoice.py +++ b/stock_picking_invoicing/models/invoice.py @@ -27,11 +27,6 @@ _logger = logging.getLogger(__name__) -INVOICE_STATE = [ - ("invoiced", "Invoiced"), - ("2binvoiced", "To Be Invoiced"), - ("none", "Not Applicable") - ] class AccountInvoice(models.Model): _inherit = "account.invoice" diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index f00b16ba02b..d01690f9dda 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -133,7 +133,6 @@ def _get_taxes(self, fiscal_position): my_taxes = taxes_ids.filtered(lambda r: r.company_id.id == self.company_id.id) my_taxes = fiscal_position.map_tax(my_taxes) my_taxes = [t.id for t in my_taxes] - _logger.debug("TAXES %s" % my_taxes) return my_taxes From 909fee2a04327e6e75b2212abf400fc5b4824f62 Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Mon, 21 Mar 2016 05:51:31 +0100 Subject: [PATCH 021/123] better management of list_price --- stock_picking_invoicing/models/stock.py | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index d01690f9dda..60ae099b1d7 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -183,7 +183,7 @@ def _get_invoice_line_vals(self, partner, inv_type): 'uos_id': uos_id, 'uom_id': uos_id, 'quantity': quantity, - 'price_unit': self._get_price_unit_invoice(inv_type), + 'price_unit': self._get_price_unit_invoice(inv_type, partner), 'invoice_line_tax_ids': [(6, 0, taxes_ids)], 'discount': 0.0, 'account_analytic_id': False, @@ -207,27 +207,34 @@ def _get_invoice_line_vals(self, partner, inv_type): @api.multi - def _get_price_unit_invoice(self, inv_type): + def _get_price_unit_invoice(self, inv_type, partner): """ Gets price unit for invoice @param move_line: Stock move lines @param type: Type of invoice @return: The price unit for the move line """ - - if type in ('in_invoice', 'in_refund'): - return move_line.product_id.price + result = 0.0 + if inv_type in ('in_invoice', 'in_refund'): + return self.product_id.price else: # If partner given, search price in its sale pricelist - if self.partner_id and self.partner_id.property_product_pricelist: - self = self.with_context( + + if partner and partner.property_product_pricelist: + product_id = self.product_id.with_context( partner=self.partner_id.id, quantity=self.product_uom_qty, date=self.date, - pricelist=self.partner_id.property_product_pricelist.id, + pricelist=partner.property_product_pricelist.id, uom=self.product_uom.id - ) - result = self.product_id.price - + ) + result = product_id.price + + else : + + result = product_id.lst_price + + _logger.debug("Calcul du prix : %s " % result) + return result @api.multi From 8fe190a439400934ea4338fec90f155e88d57247 Mon Sep 17 00:00:00 2001 From: flotho Date: Fri, 1 Apr 2016 12:58:57 +0200 Subject: [PATCH 022/123] OCA guidelines --- stock_picking_invoicing/README.rst | 61 ++++++++++++++--- stock_picking_invoicing/__init__.py | 20 +----- stock_picking_invoicing/__manifest__.py | 20 +----- stock_picking_invoicing/models/__init__.py | 20 +----- stock_picking_invoicing/models/invoice.py | 29 +-------- stock_picking_invoicing/models/stock.py | 65 ++++--------------- stock_picking_invoicing/tests/__init__.py | 20 +----- .../tests/test_picking_invoicing.py | 20 +----- stock_picking_invoicing/views/stock_view.xml | 3 - stock_picking_invoicing/wizard/__init__.py | 20 +----- .../wizard/stock_invoice_onshipping.py | 49 ++------------ 11 files changed, 86 insertions(+), 241 deletions(-) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index 425c081dc13..361c6690908 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -1,23 +1,67 @@ .. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License: AGPL-3 + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +======================= Stock picking invoicing ======================= This module allows to create invoices directly from picking, without having to use sale or purchase orders. +Installation +============ + +To install this module, you need to: + +#. Do this ... + +Configuration +============= + +To configure this module, you need to: + +#. Go to ... + +Usage +===== + +To use this module, you need to: + +#. Go to ... + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/{repo_id}/{branch} + +.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt +.. branch is "8.0" for example + +Known issues / Roadmap +====================== + +* ... + Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. -In case of trouble, please check there if your issue has already been reported. -If you spotted it first, help us smashing it by providing a detailed and welcomed feedback -`here `_. +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed `feedback +`_. Credits ======= +Images +------ + +* Odoo Community Association: `Icon `_. + Contributors ------------ @@ -27,12 +71,13 @@ Contributors * Alex Comba * Florent THOMAS + Maintainer ---------- -.. image:: http://odoo-community.org/logo.png +.. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association - :target: http://odoo-community.org + :target: https://odoo-community.org This module is maintained by the OCA. @@ -40,4 +85,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit http://odoo-community.org. +To contribute to this module, please visit https://odoo-community.org. \ No newline at end of file diff --git a/stock_picking_invoicing/__init__.py b/stock_picking_invoicing/__init__.py index f293988b892..98b3c203e60 100644 --- a/stock_picking_invoicing/__init__.py +++ b/stock_picking_invoicing/__init__.py @@ -1,22 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2013-15 Agile Business Group sagl () -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import models from . import wizard diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index 0d0ae486292..ddbe2b3cb14 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -1,22 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2013-15 Agile Business Group sagl () -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': "Stock Picking Invoicing", diff --git a/stock_picking_invoicing/models/__init__.py b/stock_picking_invoicing/models/__init__.py index 06168ef5713..7764ce8f7bd 100644 --- a/stock_picking_invoicing/models/__init__.py +++ b/stock_picking_invoicing/models/__init__.py @@ -1,22 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2013-15 Agile Business Group sagl () -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import stock from . import invoice diff --git a/stock_picking_invoicing/models/invoice.py b/stock_picking_invoicing/models/invoice.py index 39fd59bbde2..1de058c24b4 100644 --- a/stock_picking_invoicing/models/invoice.py +++ b/stock_picking_invoicing/models/invoice.py @@ -1,32 +1,9 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2013-15 Agile Business Group sagl () -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging -from openerp import _ -from openerp import api -from openerp import fields -from openerp import models -from openerp.exceptions import Warning - -_logger = logging.getLogger(__name__) - +from openerp import models, api, _ class AccountInvoice(models.Model): _inherit = "account.invoice" diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index 60ae099b1d7..eb0f78cf0e2 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -1,28 +1,9 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2013-15 Agile Business Group sagl () -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging -from openerp import _ -from openerp import api -from openerp import fields -from openerp import models +from openerp import models, api, fields, _ from openerp.exceptions import Warning _logger = logging.getLogger(__name__) @@ -47,19 +28,13 @@ def _prepare_push_apply(self, cr, uid, rule, move, context=None): res['invoice_state'] = rule.invoice_state or 'none' return res -#---------------------------------------------------------- -# Procurement Rule -#---------------------------------------------------------- + class ProcurementRule(models.Model): _inherit = 'procurement.rule' invoice_state = fields.Selection(INVOICE_STATE, string="Invoice Status", default="none") -#---------------------------------------------------------- -# Procurement Order -#---------------------------------------------------------- - class ProcurementOrder(models.Model): _inherit = "procurement.order" @@ -68,18 +43,13 @@ class ProcurementOrder(models.Model): invoice_state = fields.Selection(INVOICE_STATE, string="Invoice Status", default="none") - @api.v7 - def _run_move_create(self, cr, uid, procurement, context=None): - res = super(ProcurementOrder, self)._run_move_create(cr, uid, procurement, context=context) - res.update({'invoice_state': procurement.rule_id.invoice_state or procurement.invoice_state or 'none'}) - return res - +# @api.v7 +# def _run_move_create(self, cr, uid, procurement, context=None): +# res = super(ProcurementOrder, self)._run_move_create(cr, uid, procurement, context=context) +# res.update({'invoice_state': procurement.rule_id.invoice_state or procurement.invoice_state or 'none'}) +# return res -#---------------------------------------------------------- -# Move -#---------------------------------------------------------- - class stock_move(models.Model): _inherit = "stock.move" @@ -189,9 +159,6 @@ def _get_invoice_line_vals(self, partner, inv_type): 'account_analytic_id': False, } - #https://github.com/OCA/account-invoicing/blob/8.0/stock_picking_invoicing_unified/models/stock_move.py - - # negative value on quantity if ((inv_type == 'out_invoice' and self.location_id.usage == 'customer') or @@ -253,10 +220,6 @@ def _get_moves_taxes(self, moves, inv_type): return (is_extra_move, extra_move_tax) -#---------------------------------------------------------- -# Picking -#---------------------------------------------------------- - class StockPicking(models.Model): _inherit = "stock.picking" @@ -268,11 +231,10 @@ class StockPicking(models.Model): def set_to_be_invoiced(self): for picking in self: if picking.invoice_state == '2binvoiced': - raise Warning(_("Can't update invoice control for picking %s: " - "It's 'to be invoiced' yet") % picking.name) + raise Warning(_("Invoice control cannot be updated for picking %s as it is already set as \"To be invoiced\"") % picking.name) if picking.invoice_state in ('none', 'invoiced'): if picking.invoice_id: - raise Warning(_('Picking %s has linked invoice %s') % + raise Warning(_("Picking %s is already linked to invoice %s") % (picking.name, picking.invoice_id.number)) picking.invoice_state = '2binvoiced' for move in picking.move_lines: @@ -284,11 +246,10 @@ def set_to_be_invoiced(self): def set_invoiced(self): for picking in self: if picking.invoice_state == 'invoiced' or picking.invoice_id : - raise Warning(_("Can't update invoice control for picking %s: " - "It's already invoiced!") % picking.name) + raise Warning(_("Invoice control cannot be updated for picking %s as it is already set as \"Invoiced\"") % picking.name) if picking.invoice_state in ('2binvoiced'): if picking.invoice_id: - raise Warning(_('Picking %s has linked invoice %s') % + raise Warning(_('Picking %s is already linked to invoice %s') % (picking.name, picking.invoice_id.number)) picking.invoice_state = '2binvoiced' for move in picking.move_lines: diff --git a/stock_picking_invoicing/tests/__init__.py b/stock_picking_invoicing/tests/__init__.py index 71ff1d347c1..e089377283e 100644 --- a/stock_picking_invoicing/tests/__init__.py +++ b/stock_picking_invoicing/tests/__init__.py @@ -1,21 +1,5 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Lorenzo Battistini -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import test_picking_invoicing diff --git a/stock_picking_invoicing/tests/test_picking_invoicing.py b/stock_picking_invoicing/tests/test_picking_invoicing.py index 49a2ca92c90..6d7a85563f6 100644 --- a/stock_picking_invoicing/tests/test_picking_invoicing.py +++ b/stock_picking_invoicing/tests/test_picking_invoicing.py @@ -1,22 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 Lorenzo Battistini -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import openerp.tests.common as test_common diff --git a/stock_picking_invoicing/views/stock_view.xml b/stock_picking_invoicing/views/stock_view.xml index 3452c40feb0..7e264b0afc8 100644 --- a/stock_picking_invoicing/views/stock_view.xml +++ b/stock_picking_invoicing/views/stock_view.xml @@ -1,9 +1,6 @@ - - - stock.picking.tree.inherit stock.picking diff --git a/stock_picking_invoicing/wizard/__init__.py b/stock_picking_invoicing/wizard/__init__.py index e1dfc5ca630..ff1cf363768 100644 --- a/stock_picking_invoicing/wizard/__init__.py +++ b/stock_picking_invoicing/wizard/__init__.py @@ -1,21 +1,5 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2013-15 Agile Business Group sagl () -# -# 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import stock_invoice_onshipping diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py index 038a95c927a..72086dc534a 100644 --- a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py @@ -1,27 +1,9 @@ # -*- 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 . -# -############################################################################## +# © 2016 +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging -from openerp.tools.translate import _ -from openerp import models, fields, api +from openerp import models, fields, api, _ from openerp.exceptions import Warning from openerp.tools import config @@ -67,10 +49,10 @@ def view_init(self, fields): if pick.invoice_state != '2binvoiced': count += 1 if not pick.partner_id : - raise Warning(_('All your picking must have a partner to be invoiced!')) + raise Warning(_('All your pickings must have a partner to be invoiced!')) if len(active_ids) == count: _logger.debug("Raise ") - raise Warning(_('None of these picking lists require invoicing.')) + raise Warning(_('None of these picking require invoicing.')) _logger.debug("RESULT %s") @@ -87,27 +69,6 @@ def onchange_group(self): self.show_sale_refund_journal = bool(sale_refund_pickings) self.show_purchase_journal = bool(purchase_pickings) self.show_purchase_refund_journal = bool(purchase_refund_pickings) - -# @api.onchange('journal_id') -# def onchange_journal_id(self): -# _logger.debug("ON CHANGE") -# context = self.env.context or {} -# domain = {} -# value = {} -# active_id = context.get('active_id') -# if active_id: -# picking = self.env['stock.picking'].search(active_id) -# type = picking.picking_type_id.code -# usage = picking.move_lines[0].location_id.usage if type == 'incoming' else picking.move_lines[0].location_dest_id.usage -# journal_types = JOURNAL_TYPE_MAP.get((type, usage), ['sale', 'purchase', 'sale_refund', 'purchase_refund']) -# domain['journal_id'] = [('type', 'in', journal_types)] -# if self.journal_id: -# journal = self.env['account.journal'].search(journal_id) -# -# value['journal_type'] = journal.type -# -# return {'value': value, 'domain': domain} - @api.model From 3f72e80c1e6b5499cf28d371f71088f54b5152e9 Mon Sep 17 00:00:00 2001 From: flotho Date: Fri, 1 Apr 2016 13:02:01 +0200 Subject: [PATCH 023/123] OCA guidelines --- stock_picking_invoicing/models/stock.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index eb0f78cf0e2..c4289fd9c90 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -194,14 +194,10 @@ def _get_price_unit_invoice(self, inv_type, partner): pricelist=partner.property_product_pricelist.id, uom=self.product_uom.id ) - result = product_id.price - - else : - + result = product_id.price + else : result = product_id.lst_price - _logger.debug("Calcul du prix : %s " % result) - return result @api.multi From ee517360ae4c75be6423ad7197b6b11076758479 Mon Sep 17 00:00:00 2001 From: flotho Date: Fri, 1 Apr 2016 13:16:28 +0200 Subject: [PATCH 024/123] Add dependencies and correct library from Travis --- stock_picking_invoicing/__manifest__.py | 3 ++- stock_picking_invoicing/models/stock.py | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index ddbe2b3cb14..5e910c968dd 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -10,7 +10,8 @@ 'website': 'http://www.agilebg.com', 'license': 'AGPL-3', "depends": [ - "stock" + "stock", + "account" ], "data": [ diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index c4289fd9c90..216557b52c2 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -4,7 +4,7 @@ import logging from openerp import models, api, fields, _ -from openerp.exceptions import Warning +from openerp.exceptions import Warning as UserError _logger = logging.getLogger(__name__) @@ -227,10 +227,10 @@ class StockPicking(models.Model): def set_to_be_invoiced(self): for picking in self: if picking.invoice_state == '2binvoiced': - raise Warning(_("Invoice control cannot be updated for picking %s as it is already set as \"To be invoiced\"") % picking.name) + raise UserError(_("Invoice control cannot be updated for picking %s as it is already set as \"To be invoiced\"") % picking.name) if picking.invoice_state in ('none', 'invoiced'): if picking.invoice_id: - raise Warning(_("Picking %s is already linked to invoice %s") % + raise UserError(_("Picking %s is already linked to invoice %s") % (picking.name, picking.invoice_id.number)) picking.invoice_state = '2binvoiced' for move in picking.move_lines: @@ -242,10 +242,10 @@ def set_to_be_invoiced(self): def set_invoiced(self): for picking in self: if picking.invoice_state == 'invoiced' or picking.invoice_id : - raise Warning(_("Invoice control cannot be updated for picking %s as it is already set as \"Invoiced\"") % picking.name) + raise UserError(_("Invoice control cannot be updated for picking %s as it is already set as \"Invoiced\"") % picking.name) if picking.invoice_state in ('2binvoiced'): if picking.invoice_id: - raise Warning(_('Picking %s is already linked to invoice %s') % + raise UserError(_('Picking %s is already linked to invoice %s') % (picking.name, picking.invoice_id.number)) picking.invoice_state = '2binvoiced' for move in picking.move_lines: From 3b62894c403a855e2aff3be1b45ab2d096cf5098 Mon Sep 17 00:00:00 2001 From: flotho Date: Fri, 1 Apr 2016 13:23:44 +0200 Subject: [PATCH 025/123] Correct library from Travis --- .../wizard/stock_invoice_onshipping.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py index 72086dc534a..ce1e5cb5efa 100644 --- a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py @@ -4,7 +4,7 @@ import logging from openerp import models, fields, api, _ -from openerp.exceptions import Warning +from openerp.exceptions import Warning as UserError from openerp.tools import config @@ -49,10 +49,10 @@ def view_init(self, fields): if pick.invoice_state != '2binvoiced': count += 1 if not pick.partner_id : - raise Warning(_('All your pickings must have a partner to be invoiced!')) + raise UserError(_('All your pickings must have a partner to be invoiced!')) if len(active_ids) == count: _logger.debug("Raise ") - raise Warning(_('None of these picking require invoicing.')) + raise UserError(_('None of these picking require invoicing.')) _logger.debug("RESULT %s") @@ -149,7 +149,7 @@ def open_invoice(self): invoice_ids = self.create_invoice() if not invoice_ids: - raise Warning(_('No invoice created!')) + raise UserError(_('No invoice created!')) data = self.search([('id', 'in', [self[0].id])]) From b814d5889ea815870bfded86473621b23ee9259b Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Fri, 1 Apr 2016 14:19:34 +0200 Subject: [PATCH 026/123] Correction https://travis-ci.org/OCA/account-invoicing/jobs/120042968 --- stock_picking_invoicing/README.rst | 1 - stock_picking_invoicing/models/stock.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/stock_picking_invoicing/README.rst b/stock_picking_invoicing/README.rst index 361c6690908..72fb86d2073 100644 --- a/stock_picking_invoicing/README.rst +++ b/stock_picking_invoicing/README.rst @@ -40,7 +40,6 @@ To use this module, you need to: Known issues / Roadmap ====================== -* ... Bug Tracker =========== diff --git a/stock_picking_invoicing/models/stock.py b/stock_picking_invoicing/models/stock.py index 216557b52c2..cb1c0efd607 100644 --- a/stock_picking_invoicing/models/stock.py +++ b/stock_picking_invoicing/models/stock.py @@ -50,7 +50,7 @@ class ProcurementOrder(models.Model): # return res -class stock_move(models.Model): +class StockMove(models.Model): _inherit = "stock.move" #===================== From 7ca964e26aa2f6c86eda61dacfec4ea28e65237a Mon Sep 17 00:00:00 2001 From: "florent.thomas" Date: Fri, 15 Apr 2016 10:15:51 +0200 Subject: [PATCH 027/123] Add an option for forcing the invoice status in the wizard --- .../wizard/stock_invoice_onshipping.py | 36 ++++++++++++++++--- .../wizard/stock_invoice_onshipping_view.xml | 1 + 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py index ce1e5cb5efa..a4367408d35 100644 --- a/stock_picking_invoicing/wizard/stock_invoice_onshipping.py +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping.py @@ -50,16 +50,34 @@ def view_init(self, fields): count += 1 if not pick.partner_id : raise UserError(_('All your pickings must have a partner to be invoiced!')) - if len(active_ids) == count: - _logger.debug("Raise ") - raise UserError(_('None of these picking require invoicing.')) +# if len(active_ids) == count: +# _logger.debug("Raise ") +# self.invoice_force = True +# raise UserError(_('None of these picking require invoicing.')) _logger.debug("RESULT %s") return res - + @api.multi + def check_to_be_invoiced(self): + self.ensure_one() + count = 0 + context = self.env.context or {} + active_ids = context.get('active_ids',[]) + pick_obj = self.env['stock.picking'] + for pick in pick_obj.search([('id', 'in', active_ids)]): + if pick.invoice_state != '2binvoiced': + count += 1 + + if len(active_ids) == count and not self.invoice_force : + _logger.debug("Raise ") + self.invoice_force = True + raise UserError(_('None of these picking require invoicing.\nYou need to force the invoicing.')) + + + @api.onchange('group') def onchange_group(self): self.ensure_one() @@ -114,6 +132,7 @@ def _get_journal_type(self): group = fields.Boolean("Group by partner") invoice_date = fields.Date('Invoice Date') + invoice_force = fields.Boolean('Force Invoicing', default=False) sale_journal = fields.Many2one( comodel_name='account.journal', string='Sale Journal', @@ -146,7 +165,7 @@ def _get_journal_type(self): @api.multi def open_invoice(self): self.ensure_one() - + self.check_to_be_invoiced() invoice_ids = self.create_invoice() if not invoice_ids: raise UserError(_('No invoice created!')) @@ -182,6 +201,13 @@ def create_invoice(self): active_ids = context.get('active_ids', []) + + if self.invoice_force: + _logger.debug("Force set_invoice") + pickings = self.env['stock.picking'].search([('id', 'in', active_ids)]) + pickings.set_invoiced() + + self = self.with_context( date_inv = self.invoice_date, inv_type = inv_type diff --git a/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml b/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml index 35b13bb7e02..c5ad0359a2a 100644 --- a/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml +++ b/stock_picking_invoicing/wizard/stock_invoice_onshipping_view.xml @@ -24,6 +24,7 @@ +