diff --git a/sale_discount_display_amount/README.rst b/sale_discount_display_amount/README.rst new file mode 100644 index 00000000000..d7f8f00abe2 --- /dev/null +++ b/sale_discount_display_amount/README.rst @@ -0,0 +1 @@ +This file is going to be generated by oca-gen-addon-readme. diff --git a/sale_discount_display_amount/__init__.py b/sale_discount_display_amount/__init__.py new file mode 100644 index 00000000000..f84dcd0429d --- /dev/null +++ b/sale_discount_display_amount/__init__.py @@ -0,0 +1,3 @@ +from . import models +from .hooks import pre_init_hook +from .hooks import post_init_hook diff --git a/sale_discount_display_amount/__manifest__.py b/sale_discount_display_amount/__manifest__.py new file mode 100644 index 00000000000..f565caa0fb7 --- /dev/null +++ b/sale_discount_display_amount/__manifest__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Sale Discount Display Amount', + 'summary': """ + This addon intends to display the amount of the discount computed on + sale_order_line and sale_order level""", + 'version': '10.0.1.0.0', + 'license': 'AGPL-3', + 'author': 'ACSONE SA/NV,Odoo Community Association (OCA)', + 'website': 'http://www.acsone.eu', + 'depends': [ + 'sale' + ], + 'data': [ + 'views/sale_view.xml' + ], + 'pre_init_hook': 'pre_init_hook', + 'post_init_hook': 'post_init_hook', +} diff --git a/sale_discount_display_amount/hooks.py b/sale_discount_display_amount/hooks.py new file mode 100644 index 00000000000..47bcbb59409 --- /dev/null +++ b/sale_discount_display_amount/hooks.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging +from odoo.api import Environment +from odoo import SUPERUSER_ID + +_logger = logging.getLogger(__name__) + + +def pre_init_hook(cr): + _logger.info("Create discount columns in database") + cr.execute(""" + ALTER TABLE sale_order ADD COLUMN price_total_no_discount numeric; + """) + cr.execute(""" + ALTER TABLE sale_order ADD COLUMN discount_total numeric; + """) + cr.execute(""" + ALTER TABLE sale_order_line ADD COLUMN price_total_no_discount + numeric; + """) + cr.execute(""" + ALTER TABLE sale_order_line ADD COLUMN discount_total numeric; + """) + + +def post_init_hook(cr, registry): + _logger.info("Compute discount columns") + env = Environment(cr, SUPERUSER_ID, {}) + + query = """ + update sale_order_line + set price_total_no_discount = price_total + where discount = 0.0 + """ + cr.execute(query) + + query = """ + update sale_order + set price_total_no_discount = amount_total + """ + cr.execute(query) + + query = """ + select distinct order_id from sale_order_line where discount > 0.0; + """ + + cr.execute(query) + order_ids = cr.fetchall() + + orders = env['sale.order'].search([('id', 'in', order_ids)]) + orders.mapped('order_line')._compute_discount() diff --git a/sale_discount_display_amount/models/__init__.py b/sale_discount_display_amount/models/__init__.py new file mode 100644 index 00000000000..2d7ee6c3dc7 --- /dev/null +++ b/sale_discount_display_amount/models/__init__.py @@ -0,0 +1,2 @@ +from . import sale_order +from . import sale_order_line diff --git a/sale_discount_display_amount/models/sale_order.py b/sale_discount_display_amount/models/sale_order.py new file mode 100644 index 00000000000..3ec95d460d1 --- /dev/null +++ b/sale_discount_display_amount/models/sale_order.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class SaleOrder(models.Model): + + _inherit = 'sale.order' + + discount_total = fields.Monetary( + compute='_compute_discount', + string='Discount Subtotal', + readonly=True, + store=True) + price_total_no_discount = fields.Monetary( + compute='_compute_discount', + string='Subtotal Without Discount', + readonly=True, + store=True) + + @api.depends('order_line.discount_total', 'order_line.discount_total') + def _compute_discount(self): + for order in self: + discount_total = sum(order.order_line.mapped('discount_total')) + price_total_no_discount = sum( + order.order_line.mapped('price_total_no_discount')) + order.update({ + 'discount_total': discount_total, + 'price_total_no_discount': price_total_no_discount + }) diff --git a/sale_discount_display_amount/models/sale_order_line.py b/sale_discount_display_amount/models/sale_order_line.py new file mode 100644 index 00000000000..9958e07a1a5 --- /dev/null +++ b/sale_discount_display_amount/models/sale_order_line.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + + _inherit = 'sale.order.line' + + discount_total = fields.Monetary( + compute='_compute_amount', + string='Discount Subtotal', + readonly=True, + store=True) + price_total_no_discount = fields.Monetary( + compute='_compute_amount', + string='Subtotal Without Discount', + readonly=True, + store=True) + + def _compute_discount(self): + for line in self: + if not line.discount: + line.price_total_no_discount = line.price_total + continue + price = line.price_unit + taxes = line.tax_id.compute_all( + price, + line.order_id.currency_id, + line.product_uom_qty, + product=line.product_id, + partner=line.order_id.partner_shipping_id) + + price_total_no_discount = taxes['total_included'] + discount_total = price_total_no_discount - line.price_total + + line.update({ + 'discount_total': discount_total, + 'price_total_no_discount': price_total_no_discount + }) + + @api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id') + def _compute_amount(self): + res = super(SaleOrderLine, self)._compute_amount() + self._compute_discount() + return res diff --git a/sale_discount_display_amount/readme/CONFIGURE.rst b/sale_discount_display_amount/readme/CONFIGURE.rst new file mode 100644 index 00000000000..3f8ee007107 --- /dev/null +++ b/sale_discount_display_amount/readme/CONFIGURE.rst @@ -0,0 +1,3 @@ +To configure this module, you need to: + +#. Go to Sales/Settings and check "Allow discounts on sales order lines" diff --git a/sale_discount_display_amount/readme/CONTRIBUTORS.rst b/sale_discount_display_amount/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..4771f843212 --- /dev/null +++ b/sale_discount_display_amount/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Cédric Pigeon diff --git a/sale_discount_display_amount/readme/DESCRIPTION.rst b/sale_discount_display_amount/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..d3a9483050b --- /dev/null +++ b/sale_discount_display_amount/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +In standard Odoo only display the rate of the discount applied, never the +amount. It could be great to be able to tell the customer how much he spares. +This is the goal of this addons, it will show on a sale +order the total without the discount and the value of the discount. diff --git a/sale_discount_display_amount/readme/USAGE.rst b/sale_discount_display_amount/readme/USAGE.rst new file mode 100644 index 00000000000..a06c81b1a8c --- /dev/null +++ b/sale_discount_display_amount/readme/USAGE.rst @@ -0,0 +1,6 @@ + +To use this module, you need to: + +#. Go on a sale order +#. Set a discount on a line +#. The value of the discount is dislayed in the total section as well as the total without it. diff --git a/sale_discount_display_amount/static/description/icon.png b/sale_discount_display_amount/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/sale_discount_display_amount/static/description/icon.png differ diff --git a/sale_discount_display_amount/tests/__init__.py b/sale_discount_display_amount/tests/__init__.py new file mode 100644 index 00000000000..b1f57a33cd5 --- /dev/null +++ b/sale_discount_display_amount/tests/__init__.py @@ -0,0 +1 @@ +from . import test_discount_display_amount diff --git a/sale_discount_display_amount/tests/test_discount_display_amount.py b/sale_discount_display_amount/tests/test_discount_display_amount.py new file mode 100644 index 00000000000..4c8ee1ac239 --- /dev/null +++ b/sale_discount_display_amount/tests/test_discount_display_amount.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestDiscountDisplay(TransactionCase): + + def test_sale_discount_value(self): + product1 = self.env['product.product'].create( + {'name': 'Product TEST', + 'type': 'consu'}) + customer = self.env['res.partner'].create( + {"name": "Customer TEST", + "is_company": False, + "email": "test@tes.ttest"}) + so = self.env["sale.order"].create( + {"partner_id": customer.id}) + self.env['sale.order.line'].create( + {'order_id': so.id, + 'product_id': product1.id, + 'price_unit': 30.75}) + + first_line = so.order_line[0] + first_line.discount = 10 + + self.assertAlmostEqual(first_line.price_total_no_discount, 35.36) + self.assertAlmostEqual(first_line.discount_total, 3.53) + self.assertAlmostEqual(so.discount_total, 3.53) + self.assertAlmostEqual(so.price_total_no_discount, 35.36) diff --git a/sale_discount_display_amount/views/sale_view.xml b/sale_discount_display_amount/views/sale_view.xml new file mode 100644 index 00000000000..2878a71f7de --- /dev/null +++ b/sale_discount_display_amount/views/sale_view.xml @@ -0,0 +1,17 @@ + + + + sale.order.form (abi_sale) + sale.order + + 99 + + + + + + + + + +