From 95b3b09a8c239368e78cb94f1426046efff41c9c Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sat, 7 Nov 2015 14:36:51 +0100 Subject: [PATCH] [ADD] contract_recurring_plans ============================================== Analytic plans for contract recurring invoices ============================================== This module allows to include an analytic plan on each recurring invoice line, so if you set it, this will be taken to be transferred to the invoice instead of the analytic account of the contract. Usage ===== On the contract view, select or create an analytic distribution for the invoice recurring lines that you want. --- contract_recurring_plans/README.rst | 62 +++ contract_recurring_plans/__init__.py | 5 + contract_recurring_plans/__openerp__.py | 20 + contract_recurring_plans/i18n/es.po | 36 ++ contract_recurring_plans/models/__init__.py | 5 + .../models/account_analytic_invoice_line.py | 26 + .../static/description/icon.png | Bin 0 -> 6278 bytes .../static/description/icon.svg | 463 ++++++++++++++++++ contract_recurring_plans/tests/__init__.py | 5 + .../tests/test_contract_recurring_plans.py | 47 ++ .../account_analytic_invoice_line_view.xml | 17 + 11 files changed, 686 insertions(+) create mode 100644 contract_recurring_plans/README.rst create mode 100644 contract_recurring_plans/__init__.py create mode 100644 contract_recurring_plans/__openerp__.py create mode 100644 contract_recurring_plans/i18n/es.po create mode 100644 contract_recurring_plans/models/__init__.py create mode 100644 contract_recurring_plans/models/account_analytic_invoice_line.py create mode 100644 contract_recurring_plans/static/description/icon.png create mode 100644 contract_recurring_plans/static/description/icon.svg create mode 100644 contract_recurring_plans/tests/__init__.py create mode 100644 contract_recurring_plans/tests/test_contract_recurring_plans.py create mode 100644 contract_recurring_plans/views/account_analytic_invoice_line_view.xml diff --git a/contract_recurring_plans/README.rst b/contract_recurring_plans/README.rst new file mode 100644 index 00000000..abb1ee5a --- /dev/null +++ b/contract_recurring_plans/README.rst @@ -0,0 +1,62 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +============================================== +Analytic plans for contract recurring invoices +============================================== + +This module allows to include an analytic plan on each recurring invoice line, +so if you set it, this will be taken to be transferred to the invoice instead +of the analytic account of the contract. + +Usage +===== + +On the contract view, select or create an analytic distribution for the +invoice recurring lines that you want. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/110/8.0 + +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 +======= + +Contributors +------------ + +* Pedro M. Baeza + +Icon +---- + +* https://openclipart.org/detail/125071/pie-graph +* Subicon made by `Freepik _ from + www.flaticon.com + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://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/contract_recurring_plans/__init__.py b/contract_recurring_plans/__init__.py new file mode 100644 index 00000000..721dbe49 --- /dev/null +++ b/contract_recurring_plans/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import models diff --git a/contract_recurring_plans/__openerp__.py b/contract_recurring_plans/__openerp__.py new file mode 100644 index 00000000..739bedc6 --- /dev/null +++ b/contract_recurring_plans/__openerp__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +{ + 'name': 'Analytic plans on contracts recurring invoices', + 'version': '8.0.1.0.0', + 'category': 'Contract Management', + 'author': 'Serv. Tecnolog. Avanzados - Pedro M. Baeza, ' + 'Odoo Community Association (OCA)', + 'website': 'http://www.serviciosbaeza.com', + 'depends': [ + 'account_analytic_plans', + 'account_analytic_analysis', + ], + 'data': [ + 'views/account_analytic_invoice_line_view.xml', + ], + 'installable': True, +} diff --git a/contract_recurring_plans/i18n/es.po b/contract_recurring_plans/i18n/es.po new file mode 100644 index 00000000..240ddd74 --- /dev/null +++ b/contract_recurring_plans/i18n/es.po @@ -0,0 +1,36 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_analytic_analysis_recurring_plans +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-11-01 01:39+0000\n" +"PO-Revision-Date: 2014-11-01 01:39+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_analytic_analysis_recurring_plans +#: code:_description:0 +#: model:ir.model,name:account_analytic_analysis_recurring_plans.model_account_analytic_account +#, python-format +msgid "Analytic Account" +msgstr "Cuenta analítica" + +#. module: account_analytic_analysis_recurring_plans +#: field:account.analytic.invoice.line,analytics_id:0 +msgid "Analytic Distribution" +msgstr "Distribución analítica" + +#. module: account_analytic_analysis_recurring_plans +#: code:_description:0 +#: model:ir.model,name:account_analytic_analysis_recurring_plans.model_account_analytic_invoice_line +#, python-format +msgid "account.analytic.invoice.line" +msgstr "account.analytic.invoice.line" + diff --git a/contract_recurring_plans/models/__init__.py b/contract_recurring_plans/models/__init__.py new file mode 100644 index 00000000..5c3342b8 --- /dev/null +++ b/contract_recurring_plans/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import account_analytic_invoice_line diff --git a/contract_recurring_plans/models/account_analytic_invoice_line.py b/contract_recurring_plans/models/account_analytic_invoice_line.py new file mode 100644 index 00000000..3b0660a6 --- /dev/null +++ b/contract_recurring_plans/models/account_analytic_invoice_line.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from openerp import models, fields, api + + +class AccountAnalyticAccount(models.Model): + _inherit = "account.analytic.account" + + @api.model + def _prepare_invoice_line(self, line, invoice_id): + res = super(AccountAnalyticAccount, self)._prepare_invoice_line( + line, invoice_id) + if line.analytics_id: + res.update({'account_analytic_id': False, + 'analytics_id': line.analytics_id.id}) + return res + + +class AccountAnalyticInvoiceLine(models.Model): + _inherit = "account.analytic.invoice.line" + + analytics_id = fields.Many2one( + comodel_name='account.analytic.plan.instance', + string='Analytic Distribution') diff --git a/contract_recurring_plans/static/description/icon.png b/contract_recurring_plans/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0fab733da56d27421211828457a1181253090f21 GIT binary patch literal 6278 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 literal 0 HcmV?d00001 diff --git a/contract_recurring_plans/static/description/icon.svg b/contract_recurring_plans/static/description/icon.svg new file mode 100644 index 00000000..b52aec86 --- /dev/null +++ b/contract_recurring_plans/static/description/icon.svg @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + Pile of Golden Coins + 2010-04-09T03:27:45 + A pile of hypothetical golden coins, drawn in Inkscape. + https://openclipart.org/detail/43969/pile-of-golden-coins-by-j_alves + + + J_Alves + + + + + coin + currency + gold + money + thaler + + + + + + + + + + + diff --git a/contract_recurring_plans/tests/__init__.py b/contract_recurring_plans/tests/__init__.py new file mode 100644 index 00000000..d8b9e1ae --- /dev/null +++ b/contract_recurring_plans/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import test_contract_recurring_plans diff --git a/contract_recurring_plans/tests/test_contract_recurring_plans.py b/contract_recurring_plans/tests/test_contract_recurring_plans.py new file mode 100644 index 00000000..3f248053 --- /dev/null +++ b/contract_recurring_plans/tests/test_contract_recurring_plans.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Serv. Tecnol. Avanzados - Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +import openerp.tests.common as common + + +class TestContractRecurringPlans(common.TransactionCase): + + def setUp(self): + super(TestContractRecurringPlans, self).setUp() + self.partner = self.env['res.partner'].create({'name': 'Test'}) + self.product = self.env.ref('product.product_product_consultant') + self.uom = self.env.ref('product.product_uom_hour') + self.contract = self.env['account.analytic.account'].create({ + 'name': 'Test contract', + 'partner_id': self.partner.id, + 'type': 'contract', + 'recurring_invoices': 1, + 'recurring_interval': 1, + 'recurring_invoice_line_ids': [ + (0, 0, {'quantity': 2.0, + 'price_unit': 100.0, + 'name': 'Test', + 'product_id': self.product.id, + 'uom_id': self.uom.id})], + }) + plan = self.env['account.analytic.plan'].create({'name': 'Test'}) + self.analytics = self.env['account.analytic.plan.instance'].create( + {'plan_id': plan.id}) + + def test_invoice_without_plans(self): + self.contract.recurring_create_invoice() + invoice = self.env['account.invoice'].search( + [('partner_id', '=', self.partner.id)]) + self.assertEqual( + invoice.invoice_line[0].account_analytic_id, self.contract) + + def test_invoice_with_plans(self): + self.contract.recurring_invoice_line_ids.analytics_id = ( + self.analytics.id) + self.contract.recurring_create_invoice() + invoice = self.env['account.invoice'].search( + [('partner_id', '=', self.partner.id)]) + self.assertFalse(invoice.invoice_line[0].account_analytic_id) + self.assertEqual( + invoice.invoice_line[0].analytics_id, self.analytics) diff --git a/contract_recurring_plans/views/account_analytic_invoice_line_view.xml b/contract_recurring_plans/views/account_analytic_invoice_line_view.xml new file mode 100644 index 00000000..4d164ffd --- /dev/null +++ b/contract_recurring_plans/views/account_analytic_invoice_line_view.xml @@ -0,0 +1,17 @@ + + + + + + Contract form (with plans) + account.analytic.account + + + + + + + + + +