diff --git a/pos_discount_all/README.rst b/pos_discount_all/README.rst new file mode 100644 index 0000000000..5709a733c3 --- /dev/null +++ b/pos_discount_all/README.rst @@ -0,0 +1,165 @@ +===================================== +Point of Sale - Display All Discounts +===================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:29e859f159e20beb7c3ca10008b29d3e608f2de14125fc3aae7aee8c965c47a5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github + :target: https://github.com/OCA/pos/tree/17.0/pos_discount_all + :alt: OCA/pos +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/pos-17-0/pos-17-0-pos_discount_all + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/pos&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of point of sale module, to +display on the PoS ticket, the amount of the discount applied for this +sale. Contrary to the logic of Odoo and the OCA +(https://github.com/OCA/sale-workflow/tree/14.0/sale_discount_display_amount) +the amount of the discount is the difference between the theoretical +sale with the default price list and the actual sale amount. So it take +into accounts: + +- explicit discount set on pos.order.line. (as for odoo ``sale`` + module) +- fixed price set on pos.order.line +- discount generated by specific pricelist + +Also the module ignores in the computation of undiscounted amount lines, +the lines with a 'Discount Product'. (see the configure section.) + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +- Go to "Point of Sale > Products" +- Create or edit your discount products +- Check the box "Is a Discount" + +|image| + +.. |image| image:: https://raw.githubusercontent.com/OCA/pos/17.0/pos_discount_all/static/description/product_template_form.png + +Usage +===== + +Open your point of Sale + +Make an order. for exemple, - select the product 'Conference chair +(39.40$)' - select the pricelist -10% - add a discount of 1$ + +The total discount is 1$ + 10% \* 39.40 = 4.94$ + +|image2| + +Note, the discount displayed on the ticket is updated, to take into +account all the discount. + +|image3| + +.. |image2| image:: https://raw.githubusercontent.com/OCA/pos/17.0/pos_discount_all/static/description/order_summary.png +.. |image3| image:: https://raw.githubusercontent.com/OCA/pos/17.0/pos_discount_all/static/description/pos_receipt.png + +Development +=========== + +**Note** + +In the javascript file, we could write + +.. code:: javascript + + const PosDiscountAllOrder = () => + class extends Order { + } + +However, this code doesn't work if ``pos_sale`` module is installed. For +that reason we code the declaration as Odoo does, and add eslint +exception. + +.. code:: javascript + + // eslint-disable-next-line no-shadow + const PosDiscountAllOrder = (Order) => + // eslint-disable-next-line no-shadow + class PosDiscountAllOrder extends Order { + } + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* GRAP + +Contributors +------------ + +- Sylvain LE GAL (https://twitter.com/legalsylvain) +- `Binhex `__: + + - David Luis Mora + +Other credits +------------- + +The development of this module has been financially supported by: + +- UGESS, Union Nationale des Groupements des épiceries Sociales et + Solidaires (https://ugess.org/) + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +.. |maintainer-legalsylvain| image:: https://github.com/legalsylvain.png?size=40px + :target: https://github.com/legalsylvain + :alt: legalsylvain + +Current `maintainer `__: + +|maintainer-legalsylvain| + +This module is part of the `OCA/pos `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/pos_discount_all/__init__.py b/pos_discount_all/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/pos_discount_all/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pos_discount_all/__manifest__.py b/pos_discount_all/__manifest__.py new file mode 100644 index 0000000000..0d8d087419 --- /dev/null +++ b/pos_discount_all/__manifest__.py @@ -0,0 +1,33 @@ +# Copyright (C) 2022-Today GRAP (http://www.grap.coop) +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +{ + "name": "Point of Sale - Display All Discounts", + "summary": "Display discount amount on PoS cashier screen and print it on ticket" + "calculated from the difference between a sale with default pricelist", + "version": "17.0.1.0.1", + "category": "Point of Sale", + "maintainers": ["legalsylvain"], + "author": "GRAP,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/pos", + "license": "AGPL-3", + "depends": ["point_of_sale"], + "data": [ + "views/view_product_template.xml", + ], + "assets": { + "point_of_sale.assets": [ + "pos_discount_all/static/src/js/models.js", + "pos_discount_all/static/src/xml/OrderSummary.xml", + ], + "web.assets_tests": [ + "pos_discount_all/tests/tours/PosDiscountAllTour.tour.js", + ], + }, + "demo": [ + "demo/product_product.xml", + "demo/res_groups.xml", + ], + "installable": True, +} diff --git a/pos_discount_all/demo/product_product.xml b/pos_discount_all/demo/product_product.xml new file mode 100644 index 0000000000..86697da759 --- /dev/null +++ b/pos_discount_all/demo/product_product.xml @@ -0,0 +1,15 @@ + + + + + Discount Product + + -1.0 + + + + diff --git a/pos_discount_all/demo/res_groups.xml b/pos_discount_all/demo/res_groups.xml new file mode 100644 index 0000000000..1c861012b5 --- /dev/null +++ b/pos_discount_all/demo/res_groups.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/pos_discount_all/i18n/es.po b/pos_discount_all/i18n/es.po new file mode 100644 index 0000000000..560fb88577 --- /dev/null +++ b/pos_discount_all/i18n/es.po @@ -0,0 +1,60 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_discount_all +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-02-11 18:34+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: pos_discount_all +#: model:ir.model.fields,help:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,help:pos_discount_all.field_product_template__is_discount +msgid "" +"Check this box if you use this product to realize discount on sale. If check" +" the sale lines will be ignored when computing the amount without discount. " +"If you use 'Pos Discount' Odoo module, you should check this box for the " +"product you configured as the 'Discount Product' on your PoS config." +msgstr "" +"Marque esta casilla si utiliza este producto para realizar descuentos en " +"rebajas. Si marca las lineas de venta seran ignoradas cuando se calcule la " +"cantidad sin descuento. Si utiliza 'Pos Descuento' módulo de Odoo, debe " +"marcar esta casilla para el producto que ha configurado como el 'Producto de " +"descuento' en su configuración PoS." + +#. module: pos_discount_all +#. odoo-javascript +#: code:addons/pos_discount_all/static/src/xml/OrderSummary.xml:0 +#, python-format +msgid "Discount Amount:" +msgstr "Importe del Descuento:" + +#. module: pos_discount_all +#: model:product.template,name:pos_discount_all.product_discount_product_template +msgid "Discount Product" +msgstr "Producto con Descuento" + +#. module: pos_discount_all +#: model:ir.model.fields,field_description:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,field_description:pos_discount_all.field_product_template__is_discount +msgid "Is a Discount" +msgstr "Es un Descuento" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_pos_session +msgid "Point of Sale Session" +msgstr "Sesión del Punto de Venta" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_product_template +msgid "Product" +msgstr "Producto" diff --git a/pos_discount_all/i18n/fr.po b/pos_discount_all/i18n/fr.po new file mode 100644 index 0000000000..44a3008462 --- /dev/null +++ b/pos_discount_all/i18n/fr.po @@ -0,0 +1,55 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_discount_all +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-10 12:38+0000\n" +"Last-Translator: LESTRAT21 \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: pos_discount_all +#: model:ir.model.fields,help:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,help:pos_discount_all.field_product_template__is_discount +msgid "" +"Check this box if you use this product to realize discount on sale. If check" +" the sale lines will be ignored when computing the amount without discount. " +"If you use 'Pos Discount' Odoo module, you should check this box for the " +"product you configured as the 'Discount Product' on your PoS config." +msgstr "" + +#. module: pos_discount_all +#. odoo-javascript +#: code:addons/pos_discount_all/static/src/xml/OrderSummary.xml:0 +#, python-format +msgid "Discount Amount:" +msgstr "Montant de la réduction :" + +#. module: pos_discount_all +#: model:product.template,name:pos_discount_all.product_discount_product_template +msgid "Discount Product" +msgstr "Réduction appliquée" + +#. module: pos_discount_all +#: model:ir.model.fields,field_description:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,field_description:pos_discount_all.field_product_template__is_discount +msgid "Is a Discount" +msgstr "Est une réduction" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_pos_session +msgid "Point of Sale Session" +msgstr "Session de caisse" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_product_template +msgid "Product" +msgstr "Produit" diff --git a/pos_discount_all/i18n/it.po b/pos_discount_all/i18n/it.po new file mode 100644 index 0000000000..da8f2c3ebd --- /dev/null +++ b/pos_discount_all/i18n/it.po @@ -0,0 +1,60 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_discount_all +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-09 03:34+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: pos_discount_all +#: model:ir.model.fields,help:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,help:pos_discount_all.field_product_template__is_discount +msgid "" +"Check this box if you use this product to realize discount on sale. If check " +"the sale lines will be ignored when computing the amount without discount. " +"If you use 'Pos Discount' Odoo module, you should check this box for the " +"product you configured as the 'Discount Product' on your PoS config." +msgstr "" +"Spuntare questa opzione se si usa questo prodotto come sconto nelle vendite. " +"Se selezionata la riga di vendita verrà ignorata nel calcolare il valore " +"senza sconto. Se si usa il modulo Odoo 'Sconto POS', bisogna spuntare questa " +"opzione per il prodotto configurato come 'Prodotto sconto' nella " +"configurazione POS." + +#. module: pos_discount_all +#. odoo-javascript +#: code:addons/pos_discount_all/static/src/xml/OrderSummary.xml:0 +#, python-format +msgid "Discount Amount:" +msgstr "Importo sconto:" + +#. module: pos_discount_all +#: model:product.template,name:pos_discount_all.product_discount_product_template +msgid "Discount Product" +msgstr "Prodotto scontato" + +#. module: pos_discount_all +#: model:ir.model.fields,field_description:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,field_description:pos_discount_all.field_product_template__is_discount +msgid "Is a Discount" +msgstr "È uno sconto" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_pos_session +msgid "Point of Sale Session" +msgstr "Sessione punto vendita" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_product_template +msgid "Product" +msgstr "Prodotto" diff --git a/pos_discount_all/i18n/pos_discount_all.pot b/pos_discount_all/i18n/pos_discount_all.pot new file mode 100644 index 0000000000..89897aa130 --- /dev/null +++ b/pos_discount_all/i18n/pos_discount_all.pot @@ -0,0 +1,52 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_discount_all +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \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: pos_discount_all +#: model:ir.model.fields,help:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,help:pos_discount_all.field_product_template__is_discount +msgid "" +"Check this box if you use this product to realize discount on sale. If check" +" the sale lines will be ignored when computing the amount without discount. " +"If you use 'Pos Discount' Odoo module, you should check this box for the " +"product you configured as the 'Discount Product' on your PoS config." +msgstr "" + +#. module: pos_discount_all +#. odoo-javascript +#: code:addons/pos_discount_all/static/src/xml/OrderSummary.xml:0 +#, python-format +msgid "Discount Amount:" +msgstr "" + +#. module: pos_discount_all +#: model:product.template,name:pos_discount_all.product_discount_product_template +msgid "Discount Product" +msgstr "" + +#. module: pos_discount_all +#: model:ir.model.fields,field_description:pos_discount_all.field_product_product__is_discount +#: model:ir.model.fields,field_description:pos_discount_all.field_product_template__is_discount +msgid "Is a Discount" +msgstr "" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_pos_session +msgid "Point of Sale Session" +msgstr "" + +#. module: pos_discount_all +#: model:ir.model,name:pos_discount_all.model_product_template +msgid "Product" +msgstr "" diff --git a/pos_discount_all/models/__init__.py b/pos_discount_all/models/__init__.py new file mode 100644 index 0000000000..a34c01c8a5 --- /dev/null +++ b/pos_discount_all/models/__init__.py @@ -0,0 +1,2 @@ +from . import pos_session +from . import product_template diff --git a/pos_discount_all/models/pos_session.py b/pos_discount_all/models/pos_session.py new file mode 100644 index 0000000000..385e97295b --- /dev/null +++ b/pos_discount_all/models/pos_session.py @@ -0,0 +1,14 @@ +# Copyright (C) 2022-Today GRAP (http://www.grap.coop) +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import models + + +class PosSession(models.Model): + _inherit = "pos.session" + + def _loader_params_product_product(self): + res = super()._loader_params_product_product() + res["search_params"]["fields"].append("is_discount") + return res diff --git a/pos_discount_all/models/product_template.py b/pos_discount_all/models/product_template.py new file mode 100644 index 0000000000..3ada2184e0 --- /dev/null +++ b/pos_discount_all/models/product_template.py @@ -0,0 +1,19 @@ +# Copyright (C) 2022-Today GRAP (http://www.grap.coop) +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + is_discount = fields.Boolean( + string="Is a Discount", + help="Check this box if you use this product to realize" + " discount on sale. If check the sale lines will be" + " ignored when computing the amount without discount." + " If you use 'Pos Discount' Odoo module, you should" + " check this box for the product you configured" + " as the 'Discount Product' on your PoS config.", + ) diff --git a/pos_discount_all/pyproject.toml b/pos_discount_all/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/pos_discount_all/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/pos_discount_all/readme/CONFIGURE.md b/pos_discount_all/readme/CONFIGURE.md new file mode 100644 index 0000000000..ab1acdb5f7 --- /dev/null +++ b/pos_discount_all/readme/CONFIGURE.md @@ -0,0 +1,5 @@ +- Go to "Point of Sale \> Products" +- Create or edit your discount products +- Check the box "Is a Discount" + +![image](../static/description/product_template_form.png) diff --git a/pos_discount_all/readme/CONTRIBUTORS.md b/pos_discount_all/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..d60bf3de10 --- /dev/null +++ b/pos_discount_all/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- Sylvain LE GAL () +- [Binhex](https://binhex.cloud//com): + - David Luis Mora \<\> diff --git a/pos_discount_all/readme/CREDITS.md b/pos_discount_all/readme/CREDITS.md new file mode 100644 index 0000000000..4f833c6217 --- /dev/null +++ b/pos_discount_all/readme/CREDITS.md @@ -0,0 +1,4 @@ +The development of this module has been financially supported by: + +- UGESS, Union Nationale des Groupements des épiceries Sociales et + Solidaires () diff --git a/pos_discount_all/readme/DESCRIPTION.md b/pos_discount_all/readme/DESCRIPTION.md new file mode 100644 index 0000000000..1971572f33 --- /dev/null +++ b/pos_discount_all/readme/DESCRIPTION.md @@ -0,0 +1,14 @@ +This module extends the functionality of point of sale module, to +display on the PoS ticket, the amount of the discount applied for this +sale. Contrary to the logic of Odoo and the OCA +() +the amount of the discount is the difference between the theoretical +sale with the default price list and the actual sale amount. So it take +into accounts: + +- explicit discount set on pos.order.line. (as for odoo `sale` module) +- fixed price set on pos.order.line +- discount generated by specific pricelist + +Also the module ignores in the computation of undiscounted amount lines, +the lines with a 'Discount Product'. (see the configure section.) diff --git a/pos_discount_all/readme/DEVELOP.md b/pos_discount_all/readme/DEVELOP.md new file mode 100644 index 0000000000..ec9e8cf556 --- /dev/null +++ b/pos_discount_all/readme/DEVELOP.md @@ -0,0 +1,21 @@ +**Note** + +In the javascript file, we could write + +``` javascript +const PosDiscountAllOrder = () => + class extends Order { + } +``` + +However, this code doesn't work if `pos_sale` module is installed. For +that reason we code the declaration as Odoo does, and add eslint +exception. + +``` javascript +// eslint-disable-next-line no-shadow +const PosDiscountAllOrder = (Order) => + // eslint-disable-next-line no-shadow + class PosDiscountAllOrder extends Order { + } +``` diff --git a/pos_discount_all/readme/USAGE.md b/pos_discount_all/readme/USAGE.md new file mode 100644 index 0000000000..4d0c3d3d5d --- /dev/null +++ b/pos_discount_all/readme/USAGE.md @@ -0,0 +1,13 @@ +Open your point of Sale + +Make an order. for exemple, - select the product 'Conference chair +(39.40\$)' - select the pricelist -10% - add a discount of 1\$ + +The total discount is 1\$ + 10% \* 39.40 = 4.94\$ + +![image2](../static/description/order_summary.png) + +Note, the discount displayed on the ticket is updated, to take into +account all the discount. + +![image3](../static/description/pos_receipt.png) diff --git a/pos_discount_all/static/description/icon.png b/pos_discount_all/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/pos_discount_all/static/description/icon.png differ diff --git a/pos_discount_all/static/description/index.html b/pos_discount_all/static/description/index.html new file mode 100644 index 0000000000..dc21ce3902 --- /dev/null +++ b/pos_discount_all/static/description/index.html @@ -0,0 +1,493 @@ + + + + + + +Point of Sale - Display All Discounts + + + +
+

Point of Sale - Display All Discounts

+ + +

Beta License: AGPL-3 OCA/pos Translate me on Weblate Try me on Runboat

+

This module extends the functionality of point of sale module, to +display on the PoS ticket, the amount of the discount applied for this +sale. Contrary to the logic of Odoo and the OCA +(https://github.com/OCA/sale-workflow/tree/14.0/sale_discount_display_amount) +the amount of the discount is the difference between the theoretical +sale with the default price list and the actual sale amount. So it take +into accounts:

+
    +
  • explicit discount set on pos.order.line. (as for odoo sale +module)
  • +
  • fixed price set on pos.order.line
  • +
  • discount generated by specific pricelist
  • +
+

Also the module ignores in the computation of undiscounted amount lines, +the lines with a ‘Discount Product’. (see the configure section.)

+

Table of contents

+ +
+

Configuration

+
    +
  • Go to “Point of Sale > Products”
  • +
  • Create or edit your discount products
  • +
  • Check the box “Is a Discount”
  • +
+

image

+
+
+

Usage

+

Open your point of Sale

+

Make an order. for exemple, - select the product ‘Conference chair +(39.40$)’ - select the pricelist -10% - add a discount of 1$

+

The total discount is 1$ + 10% * 39.40 = 4.94$

+

image2

+

Note, the discount displayed on the ticket is updated, to take into +account all the discount.

+

image3

+
+
+

Development

+

Note

+

In the javascript file, we could write

+
+const PosDiscountAllOrder = () =>
+    class extends Order {
+    }
+
+

However, this code doesn’t work if pos_sale module is installed. For +that reason we code the declaration as Odoo does, and add eslint +exception.

+
+// eslint-disable-next-line no-shadow
+const PosDiscountAllOrder = (Order) =>
+    // eslint-disable-next-line no-shadow
+    class PosDiscountAllOrder extends Order {
+    }
+
+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • GRAP
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The development of this module has been financially supported by:

+
    +
  • UGESS, Union Nationale des Groupements des épiceries Sociales et +Solidaires (https://ugess.org/)
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainer:

+

legalsylvain

+

This module is part of the OCA/pos project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/pos_discount_all/static/description/order_summary.png b/pos_discount_all/static/description/order_summary.png new file mode 100644 index 0000000000..69c8e54b8f Binary files /dev/null and b/pos_discount_all/static/description/order_summary.png differ diff --git a/pos_discount_all/static/description/pos_receipt.png b/pos_discount_all/static/description/pos_receipt.png new file mode 100644 index 0000000000..7c9ba11c68 Binary files /dev/null and b/pos_discount_all/static/description/pos_receipt.png differ diff --git a/pos_discount_all/static/description/product_template_form.png b/pos_discount_all/static/description/product_template_form.png new file mode 100644 index 0000000000..7703dace2e Binary files /dev/null and b/pos_discount_all/static/description/product_template_form.png differ diff --git a/pos_discount_all/static/src/js/models.js b/pos_discount_all/static/src/js/models.js new file mode 100644 index 0000000000..6f057eb3f3 --- /dev/null +++ b/pos_discount_all/static/src/js/models.js @@ -0,0 +1,101 @@ +/* + Copyright (C) 2022-Today GRAP (http://www.grap.coop) + @author Sylvain LE GAL (https://twitter.com/legalsylvain) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +*/ + +odoo.define("pos_discount_all.models", function (require) { + "use strict"; + + const {Order, Orderline} = require("point_of_sale.models"); + const Registries = require("point_of_sale.Registries"); + const {round_precision: round_pr} = require("web.utils"); + + // eslint-disable-next-line no-shadow + const PosDiscountAllOrder = (Order) => + // eslint-disable-next-line no-shadow + class PosDiscountAllOrder extends Order { + // eslint-disable-line no-shadow + // @override + _get_ignored_product_ids_total_discount() { + const productIds = super._get_ignored_product_ids_total_discount( + ...arguments + ); + _.map(this.pos.db.product_by_id, function (product) { + if (product.is_discount) { + productIds.push(product.id); + } + }); + return productIds; + } + + get_total_with_tax_without_any_discount() { + return round_pr( + this.orderlines.reduce(function (sum, orderLine) { + return ( + sum + + orderLine.get_total_without_any_discount().total_included + ); + }, 0), + this.pos.currency.rounding + ); + } + + get_discount_amount_with_tax_without_any_discount() { + return round_pr( + this.get_total_with_tax_without_any_discount() - + this.get_total_with_tax(), + this.pos.currency.rounding + ); + } + + export_for_printing() { + var receipt = super.export_for_printing(...arguments); + receipt.total_discount = + this.get_discount_amount_with_tax_without_any_discount(); + return receipt; + } + }; + + Registries.Model.extend(Order, PosDiscountAllOrder); + + // eslint-disable-next-line no-shadow + const PosDiscountAllOrderLine = (Orderline) => + // eslint-disable-next-line no-shadow + class PosDiscountAllOrderLine extends Orderline { + // eslint-disable-line no-shadow + get_total_without_any_discount() { + var product = this.get_product(); + const ignored_product_ids = + this.order._get_ignored_product_ids_total_discount(); + if (ignored_product_ids.includes(product.id)) { + return { + total_excluded: 0.0, + total_included: 0.0, + }; + } + var price_unit_without_any_discount = product.get_price( + this.pos.default_pricelist, + this.get_quantity() + ); + var taxes_ids = this.tax_ids || product.taxes_id; + taxes_ids = _.filter(taxes_ids, (t) => t in this.pos.taxes_by_id); + var product_taxes = this.pos.get_taxes_after_fp( + taxes_ids, + this.order.fiscal_position + ); + var all_taxes_without_any_discount = this.compute_all( + product_taxes, + price_unit_without_any_discount, + this.get_quantity(), + this.pos.currency.rounding + ); + return { + total_excluded: all_taxes_without_any_discount.total_excluded, + total_included: all_taxes_without_any_discount.total_included, + }; + } + }; + + Registries.Model.extend(Orderline, PosDiscountAllOrderLine); +}); diff --git a/pos_discount_all/static/src/xml/OrderSummary.xml b/pos_discount_all/static/src/xml/OrderSummary.xml new file mode 100644 index 0000000000..07b55ea07a --- /dev/null +++ b/pos_discount_all/static/src/xml/OrderSummary.xml @@ -0,0 +1,28 @@ + + + + + + + +
+ Discount Amount: + + + +
+
+
+ +
diff --git a/pos_discount_all/tests/__init__.py b/pos_discount_all/tests/__init__.py new file mode 100644 index 0000000000..d9b96c4fa5 --- /dev/null +++ b/pos_discount_all/tests/__init__.py @@ -0,0 +1 @@ +from . import test_module diff --git a/pos_discount_all/tests/test_module.py b/pos_discount_all/tests/test_module.py new file mode 100644 index 0000000000..e05a4bb7ab --- /dev/null +++ b/pos_discount_all/tests/test_module.py @@ -0,0 +1,64 @@ +# Copyright (C) 2022-Today GRAP (http://www.grap.coop) +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + + +from odoo.tests import tagged + +from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon + + +@tagged("post_install", "-at_install") +class TestUi(TestPointOfSaleHttpCommon): + def test_pos_discount_all(self): + pricelist = self.env["product.pricelist"].create( + { + "name": "Pricelist -10%", + } + ) + self.env["product.pricelist.item"].create( + { + "pricelist_id": pricelist.id, + "name": "Pricelist Item -10%", + "applied_on": "3_global", + "compute_price": "percentage", + "percent_price": 10, + } + ) + self.main_pos_config.write( + { + "use_pricelist": True, + "available_pricelist_ids": [(4, pricelist.id)], + } + ) + + # Make the test compatible with pos_minimize_menu + if "iface_important_buttons" in self.main_pos_config._fields: + self.main_pos_config.iface_important_buttons = "SetPricelistButton" + + self.env["product.product"].create( + { + "name": "Generic Product", + "available_in_pos": True, + "list_price": 10.0, + "taxes_id": False, + } + ) + + self.env["product.product"].create( + { + "name": "Discount Product", + "is_discount": True, + "available_in_pos": True, + "list_price": -1.0, + "taxes_id": False, + } + ) + + self.main_pos_config.open_ui() + + self.start_tour( + f"/pos/ui?config_id={self.main_pos_config.id}", + "PosDiscountAllTour", + login="accountman", + ) diff --git a/pos_discount_all/tests/tours/PosDiscountAllTour.tour.js b/pos_discount_all/tests/tours/PosDiscountAllTour.tour.js new file mode 100644 index 0000000000..25c6ee6cd7 --- /dev/null +++ b/pos_discount_all/tests/tours/PosDiscountAllTour.tour.js @@ -0,0 +1,78 @@ +/* + Copyright (C) 2022-Today GRAP (http://www.grap.coop) + @author Sylvain LE GAL (https://twitter.com/legalsylvain) + License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +*/ +/* eslint-disable no-empty-function */ +odoo.define("pos_discount_all.tour.PosDiscountAllTour", function (require) { + "use strict"; + + const Tour = require("web_tour.tour"); + + var steps = [ + { + content: "Test pos_discount_all: Waiting for loading to finish", + trigger: "body:not(:has(.loader))", + run: () => {}, + }, + { + content: "Test pos_discount_all: Close Opening cashbox popup", + trigger: "div.opening-cash-control .button:contains('Open session')", + }, + { + content: "Test pos_discount_all: Leave category displayed by default", + trigger: ".breadcrumb-home", + run: () => {}, + }, + { + content: "Test pos_discount_all: Order a 'Discount Product' (price -1.0)", + trigger: ".product-list .product-name:contains('Discount Product')", + }, + { + content: "Test pos_discount_all: Check correct amount of discount value", + trigger: ".discount-amount:contains('1.0')", + }, + { + content: "Test pos_discount_all: Order one 'Generic Product' (price 10.0)", + trigger: ".product-list .product-name:contains('Generic Product')", + }, + { + content: "Test pos_discount_all: Change to price mode", + trigger: ".numpad button:contains('Price')", + }, + { + content: + "Test pos_discount_all: manually override the unit price of 'Generic Product' (price 5.0)", + trigger: ".numpad button.input-button:visible:contains('5')", + }, + { + content: "Test pos_discount_all: Check correct amount of discount value", + trigger: ".discount-amount:contains('6.0')", + }, + { + content: "Test pos_discount_all: open Pricelist popUp", + trigger: ".control-button.o_pricelist_button", + }, + { + content: "Test pos_discount_all: select 'Pricelist -10%' pricelist", + trigger: ".selection-item:contains('Pricelist -10%')", + }, + { + content: "Test pos_discount_all: Check correct amount of discount value", + trigger: ".discount-amount:contains('5.90')", + }, + { + content: "Test pos_discount_all: Close the Point of Sale frontend", + trigger: ".header-button", + }, + { + content: "Test pos_discount_all: Confirm closing the frontend", + trigger: ".header-button", + run: () => {}, + }, + ]; + + Tour.register("PosDiscountAllTour", {test: true, url: "/pos/ui"}, steps); +}); + +/* */ diff --git a/pos_discount_all/views/view_product_template.xml b/pos_discount_all/views/view_product_template.xml new file mode 100644 index 0000000000..97e51ebf89 --- /dev/null +++ b/pos_discount_all/views/view_product_template.xml @@ -0,0 +1,20 @@ + + + + + product.template + + + + + + + + + +