From 86c2c91f4b272eba461dea6a294196c48169fa4b Mon Sep 17 00:00:00 2001 From: AngelMoya-Domatix Date: Wed, 2 Sep 2015 15:30:11 +0200 Subject: [PATCH] ADD contract_discount module --- contract_discount/README.rst | 58 ++++++++++++++++++ contract_discount/__init__.py | 3 + contract_discount/__openerp__.py | 38 ++++++++++++ contract_discount/i18n/contract_discount.pot | 38 ++++++++++++ contract_discount/i18n/es.po | 39 ++++++++++++ contract_discount/models/__init__.py | 2 + contract_discount/models/contract.py | 52 ++++++++++++++++ contract_discount/test/contract_discount.yml | 49 +++++++++++++++ contract_discount/tests/__init__.py | 3 + .../tests/test_contract_discount.py | 59 +++++++++++++++++++ contract_discount/views/contract_view.xml | 19 ++++++ 11 files changed, 360 insertions(+) create mode 100644 contract_discount/README.rst create mode 100644 contract_discount/__init__.py create mode 100644 contract_discount/__openerp__.py create mode 100644 contract_discount/i18n/contract_discount.pot create mode 100644 contract_discount/i18n/es.po create mode 100644 contract_discount/models/__init__.py create mode 100644 contract_discount/models/contract.py create mode 100644 contract_discount/test/contract_discount.yml create mode 100644 contract_discount/tests/__init__.py create mode 100644 contract_discount/tests/test_contract_discount.py create mode 100644 contract_discount/views/contract_view.xml diff --git a/contract_discount/README.rst b/contract_discount/README.rst new file mode 100644 index 00000000..2b5b78ff --- /dev/null +++ b/contract_discount/README.rst @@ -0,0 +1,58 @@ +.. 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 + +================= +Contract Discount +================= + +This module was written to extend the functionality of contracts to support set a discount on contract invoice lines. + +Configuration +============= + +To configure this module, you need to go to settings -> Configuration -> Sales and activate "Allow setting a discount on the sales order lines" to see discount in contracts. + +Usage +===== + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/contract/8.0 + +.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt +.. branch is "8.0" for example + +For further information, please visit: + +* https://www.odoo.com/forum/help-1 + +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 +------------ + +* Angel Moya + + +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. \ No newline at end of file diff --git a/contract_discount/__init__.py b/contract_discount/__init__.py new file mode 100644 index 00000000..c98792e9 --- /dev/null +++ b/contract_discount/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import models +from . import tests diff --git a/contract_discount/__openerp__.py b/contract_discount/__openerp__.py new file mode 100644 index 00000000..1e8d2496 --- /dev/null +++ b/contract_discount/__openerp__.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +############################################################################### +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015 Domatix (). +# +# 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': 'Contract Discount', + 'summary': 'Discounts for contracts and their invoices', + 'version': '8.0.1.0.0', + 'author': 'Domatix, Odoo Community Association (OCA)', + 'website': 'http://www.domatix.com', + 'depends': ['account_analytic_analysis'], + 'category': 'Sales Management', + 'license': 'AGPL-3', + 'data': [ + 'views/contract_view.xml', + ], + 'test': ['test/contract_discount.yml'], + 'installable': True, + 'auto_install': False, +} diff --git a/contract_discount/i18n/contract_discount.pot b/contract_discount/i18n/contract_discount.pot new file mode 100644 index 00000000..566b127d --- /dev/null +++ b/contract_discount/i18n/contract_discount.pot @@ -0,0 +1,38 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_discount +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-09-16 15:14+0000\n" +"PO-Revision-Date: 2015-09-16 15:14+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: contract_discount +#: model:ir.model,name:contract_discount.model_account_analytic_account +msgid "Analytic Account" +msgstr "" + +#. module: contract_discount +#: field:account.analytic.invoice.line,discount:0 +msgid "Discount (%)" +msgstr "" + +#. module: contract_discount +#: code:addons/contract_discount/models/contract.py:40 +#, python-format +msgid "Discount should be less or equal to 100" +msgstr "" + +#. module: contract_discount +#: help:account.analytic.invoice.line,discount:0 +msgid "Discount that is applied in generated invoices. It should be less or equal to 100" +msgstr "" + diff --git a/contract_discount/i18n/es.po b/contract_discount/i18n/es.po new file mode 100644 index 00000000..78b904d6 --- /dev/null +++ b/contract_discount/i18n/es.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * contract_discount +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-09-16 15:14+0000\n" +"PO-Revision-Date: 2015-09-16 17:15+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"Language: es\n" +"X-Generator: Poedit 1.7.5\n" + +#. module: contract_discount +#: model:ir.model,name:contract_discount.model_account_analytic_account +msgid "Analytic Account" +msgstr "Cuenta analĂ­tica" + +#. module: contract_discount +#: field:account.analytic.invoice.line,discount:0 +msgid "Discount (%)" +msgstr "Descuento (%)" + +#. module: contract_discount +#: code:addons/contract_discount/models/contract.py:40 +#, python-format +msgid "Discount should be less or equal to 100" +msgstr "El descuento debe ser menor o igual que 100" + +#. module: contract_discount +#: help:account.analytic.invoice.line,discount:0 +msgid "Discount that is applied in generated invoices. It should be less or equal to 100" +msgstr "El descuento se aplica en las facturas generadas. Debe ser menor o igual que 100" diff --git a/contract_discount/models/__init__.py b/contract_discount/models/__init__.py new file mode 100644 index 00000000..b82ea877 --- /dev/null +++ b/contract_discount/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import contract diff --git a/contract_discount/models/contract.py b/contract_discount/models/contract.py new file mode 100644 index 00000000..ef5fd665 --- /dev/null +++ b/contract_discount/models/contract.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +from openerp import models, fields, api +from openerp.addons.decimal_precision import decimal_precision as dp +from openerp.exceptions import ValidationError + +from openerp.tools.translate import _ + +from openerp.osv import fields as old_fields + + +class AccountAnalyticInvoiceLine(models.Model): + _inherit = "account.analytic.invoice.line" + + def _amount_line(self, cr, uid, ids, prop, unknow_none, unknow_dict, + context=None): + res = super(AccountAnalyticInvoiceLine, self)._amount_line( + cr, uid, ids, prop, unknow_none, unknow_dict, context=context) + for line in self.browse(cr, uid, ids, context=context): + discount = (line.discount or 0) / 100 + res[line.id] = res[line.id] * (1 - discount) + return res + + discount = fields.Float( + string='Discount (%)', + digits=dp.get_precision('Discount'), + copy=True, + help='Discount that is applied in generated invoices.' + ' It should be less or equal to 100') + + _columns = { + 'price_subtotal': old_fields.function( + _amount_line, string='Sub Total', + type="float", + digits_compute=dp.get_precision('Account')), + } + + @api.one + @api.constrains('discount') + def _check_discount(self): + if self.discount > 100: + raise ValidationError(_("Discount should be less or equal to 100")) + + +class AccountAnalyticAccount(models.Model): + _inherit = 'account.analytic.account' + + @api.model + def _prepare_invoice_line(self, line, fiscal_position): + res = super(AccountAnalyticAccount, self)._prepare_invoice_line( + line, fiscal_position) + res['discount'] = line.discount or 0 + return res diff --git a/contract_discount/test/contract_discount.yml b/contract_discount/test/contract_discount.yml new file mode 100644 index 00000000..3cefb475 --- /dev/null +++ b/contract_discount/test/contract_discount.yml @@ -0,0 +1,49 @@ +- + In order to test Contract Recurrent Invoice I create a new Contract with 25% discount +- + !record {model: account.analytic.account, id: contract_main_25}: + name: Maintenance of Servers + company_id: base.main_company + partner_id: base.main_partner + type: contract + recurring_invoices : 1 + recurring_interval : 1 + recurring_invoice_line_ids: + - quantity: 2.0 + price_unit: 100.0 + discount: 25.0 + name: Database Administration 25 + product_id: product.product_product_consultant + uom_id: product.product_uom_hour + - quantity: 2.0 + price_unit: 100.0 + discount: 50.0 + name: Database Administration 50 + product_id: product.product_product_consultant + uom_id: product.product_uom_hour +- + I test the contract +- + !python {model: account.analytic.account}: | + aid = ref('contract_discount.contract_main_25') + contract = self.browse(cr, uid, aid,context=context) + assert contract.recurring_invoice_line_ids[0].discount == 25, "The line discount (%s)is different than 25!"%(contract.recurring_invoice_line_ids[0].discount,) + assert contract.recurring_invoice_line_ids[0].price_subtotal == 150.0, "The price subtotal (%s)is different than 150!"%(contract.recurring_invoice_line_ids[0].price_subtotal,) + assert contract.recurring_invoice_line_ids[1].discount == 50, "The line discount (%s)is different than 50!"%(contract.recurring_invoice_line_ids[1].discount,) + assert contract.recurring_invoice_line_ids[1].price_subtotal == 100, "The price subtotal (%s)is different than 100!"%(contract.recurring_invoice_line_ids[1].price_subtotal,) +- + I generate all invoices from contracts having recurring invoicing +- + !python {model: account.analytic.account}: | + self.recurring_create_invoice(cr, uid, []) +- + I test the generated invoice +- + !python {model: account.invoice}: | + aid = ref('contract_discount.contract_main_25') + ids = self.search(cr, uid, [('invoice_line.account_analytic_id','=',aid)], context=context) + assert len(ids)>=1, 'No invoice created for the contract' + for invoice in self.browse(cr, uid, ids,context=context): + assert invoice.invoice_line[0].discount == 25, "The invoice discount (%s)is different than 25!"%(invoice.invoice_line[0].discount,) + assert invoice.invoice_line[1].discount == 50, "The invoice discount (%s)is different than 50!"%(invoice.invoice_line[1].discount,) + assert invoice.amount_untaxed == 250.0, "The invoice total (%s)is different than 250!"%(invoice.amount_untaxed,) diff --git a/contract_discount/tests/__init__.py b/contract_discount/tests/__init__.py new file mode 100644 index 00000000..db9cc41a --- /dev/null +++ b/contract_discount/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import test_contract_discount diff --git a/contract_discount/tests/test_contract_discount.py b/contract_discount/tests/test_contract_discount.py new file mode 100644 index 00000000..155d5c04 --- /dev/null +++ b/contract_discount/tests/test_contract_discount.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +import openerp.tests.common as common +from openerp.exceptions import ValidationError + + +def create_simple_contract(self, discount=0): + + partner_id = self.ref('base.res_partner_2') + product_id = self.ref('product.product_product_consultant') + uom_id = self.ref('product.product_uom_hour') + + line_values = [(0, 0, {'quantity': 2.0, + 'price_unit': 100.0, + 'discount': discount, + 'name': 'Database Administration 25', + 'product_id': product_id, + 'uom_id': uom_id, + })] + values = { + 'name': 'Maintenance of Servers', + 'partner_id': partner_id, + 'type': 'contract', + 'recurring_invoices': 1, + 'recurring_interval': 1, + 'recurring_invoice_line_ids': line_values, + } + + return self.env['account.analytic.account']\ + .create(values) + + +class TestContractDiscount(common.TransactionCase): + + def setUp(self): + super(TestContractDiscount, self).setUp() + + def test_create_simple_contract_without_discount(self): + """Create contract without discount""" + create_simple_contract(self) + + def test_create_simple_contract_with_discount(self): + """Create contract with discount""" + create_simple_contract(self, 50) + create_simple_contract(self, 100) + + def test_create_simple_contract_with_negative_discount(self): + """Create contract with negative discount""" + create_simple_contract(self, -10) + + def test_discount_greater_than_100_error(self): + """Create or write contract with greater than 100 discount""" + contract = create_simple_contract(self) + lines = contract.recurring_invoice_line_ids + with self.assertRaises(ValidationError): + lines.write({'discount': 110}) + + with self.assertRaises(ValidationError): + create_simple_contract(self, 150) diff --git a/contract_discount/views/contract_view.xml b/contract_discount/views/contract_view.xml new file mode 100644 index 00000000..aeb781ca --- /dev/null +++ b/contract_discount/views/contract_view.xml @@ -0,0 +1,19 @@ + + + + + + account.analytic.account.invoice.form.extension.form + + account.analytic.account + + + + + + + + + + \ No newline at end of file