diff --git a/README.md b/README.md index 3fbd76cead..fcc5dbed29 100644 --- a/README.md +++ b/README.md @@ -21,20 +21,30 @@ Available addons ---------------- addon | version | maintainers | summary --- | --- | --- | --- -[pos_customer_comment](pos_customer_comment/) | 16.0.1.0.0 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Display Customer comment in the PoS front office and allow to edit and save it by the cashier +[pos_customer_comment](pos_customer_comment/) | 16.0.1.0.2 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Display Customer comment in the PoS front office and allow to edit and save it by the cashier [pos_default_partner](pos_default_partner/) | 16.0.1.0.0 | | Add a default customer in pos order -[pos_edit_order_line](pos_edit_order_line/) | 16.0.1.0.0 | | POS Edit Order Line +[pos_discount_all](pos_discount_all/) | 16.0.1.0.1 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Display discount amount on PoS cashier screen and print it on ticketcalculated from the difference between a sale with default pricelist +[pos_edit_order_line](pos_edit_order_line/) | 16.0.1.0.1 | | POS Edit Order Line [pos_escpos_status](pos_escpos_status/) | 16.0.1.0.0 | | Point of sale: fetch status for 'escpos' driver [pos_global_discount_in_line](pos_global_discount_in_line/) | 16.0.1.0.0 | | Order discount in line instead of discount product [pos_lot_barcode](pos_lot_barcode/) | 16.0.1.0.0 | | Scan barcode to enter lot/serial numbers [pos_lot_selection](pos_lot_selection/) | 16.0.1.0.0 | | POS Lot Selection -[pos_order_remove_line](pos_order_remove_line/) | 16.0.1.0.0 | [![robyf70](https://github.com/robyf70.png?size=30px)](https://github.com/robyf70) | Add button to remove POS order line. +[pos_loyalty_redeem_payment](pos_loyalty_redeem_payment/) | 16.0.1.0.0 | | Use vouchers as payment method in pos orders +[pos_margin](pos_margin/) | 16.0.1.0.1 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Margin on PoS Order +[pos_membership](pos_membership/) | 16.0.1.0.0 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Implement features of membership module in the Point of sale UI. +[pos_minimize_menu](pos_minimize_menu/) | 16.0.1.0.0 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Reduce size of the main menu of the point of sale. +[pos_order_remove_line](pos_order_remove_line/) | 16.0.1.2.0 | [![robyf70](https://github.com/robyf70.png?size=30px)](https://github.com/robyf70) | Add button to remove POS order line. [pos_order_reorder](pos_order_reorder/) | 16.0.0.1.0 | [![GabbasovDinar](https://github.com/GabbasovDinar.png?size=30px)](https://github.com/GabbasovDinar) [![CetmixGitDrone](https://github.com/CetmixGitDrone.png?size=30px)](https://github.com/CetmixGitDrone) | Simple Re-order in the Point of Sale -[pos_order_to_sale_order](pos_order_to_sale_order/) | 16.0.1.0.2 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | PoS Order To Sale Order +[pos_order_to_sale_order](pos_order_to_sale_order/) | 16.0.1.0.5 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | PoS Order To Sale Order +[pos_order_to_sale_order_report](pos_order_to_sale_order_report/) | 16.0.1.0.0 | [![GabbasovDinar](https://github.com/GabbasovDinar.png?size=30px)](https://github.com/GabbasovDinar) [![CetmixGitDrone](https://github.com/CetmixGitDrone.png?size=30px)](https://github.com/CetmixGitDrone) | Report will be downloaded after the sales order is created. +[pos_partner_birthdate](pos_partner_birthdate/) | 16.0.1.0.2 | [![ecino](https://github.com/ecino.png?size=30px)](https://github.com/ecino) | Adds the birthdate in the customer screen of POS +[pos_partner_firstname](pos_partner_firstname/) | 16.0.1.0.0 | [![robyf70](https://github.com/robyf70.png?size=30px)](https://github.com/robyf70) | POS Support of partner firstname +[pos_payment_change](pos_payment_change/) | 16.0.1.0.0 | [![legalsylvain](https://github.com/legalsylvain.png?size=30px)](https://github.com/legalsylvain) | Allow cashier to change order payments, as long as the session is not closed. [pos_payment_terminal](pos_payment_terminal/) | 16.0.1.0.1 | | Point of sale: support generic payment terminal [pos_product_display_default_code](pos_product_display_default_code/) | 16.0.1.0.0 | | pos: display product default code before product name [pos_product_quick_info](pos_product_quick_info/) | 16.0.1.0.0 | [![GabbasovDinar](https://github.com/GabbasovDinar.png?size=30px)](https://github.com/GabbasovDinar) [![CetmixGitDrone](https://github.com/CetmixGitDrone.png?size=30px)](https://github.com/CetmixGitDrone) | Display product info by one click in Point of Sale [pos_receipt_hide_price](pos_receipt_hide_price/) | 16.0.1.0.0 | | Add button to remove price from receipt. +[pos_stock_available_online](pos_stock_available_online/) | 16.0.1.0.0 | [![GabbasovDinar](https://github.com/GabbasovDinar.png?size=30px)](https://github.com/GabbasovDinar) [![CetmixGitDrone](https://github.com/CetmixGitDrone.png?size=30px)](https://github.com/CetmixGitDrone) | Show the available quantity of products in the Point of Sale [//]: # (end addons) diff --git a/pos_customer_comment/README.rst b/pos_customer_comment/README.rst index 9bd0128c8d..e29516eabe 100644 --- a/pos_customer_comment/README.rst +++ b/pos_customer_comment/README.rst @@ -2,10 +2,13 @@ Point of Sale - Cashier Comment =============================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:cb7637ba4fd67a9f26be712fb0ff62d674ebbc6c8c7a4c3425288ce917f504da + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ Point of Sale - Cashier Comment .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/pos-16-0/pos-16-0-pos_customer_comment :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/184/16.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/pos&target_branch=16.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module extends the functionality of point of sale module, to allow display and edit customer note field in the point of sale UI for the cashier. @@ -63,7 +66,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 +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. @@ -80,6 +83,7 @@ Contributors ~~~~~~~~~~~~ * Sylvain LE GAL (https://twitter.com/legalsylvain) +* Juan Carlos Bonilla Other credits ~~~~~~~~~~~~~ diff --git a/pos_customer_comment/__manifest__.py b/pos_customer_comment/__manifest__.py index 4872cbb5c3..05efa8b169 100644 --- a/pos_customer_comment/__manifest__.py +++ b/pos_customer_comment/__manifest__.py @@ -6,7 +6,7 @@ "name": "Point of Sale - Cashier Comment", "summary": "Display Customer comment in the PoS front office and allow" " to edit and save it by the cashier", - "version": "16.0.1.0.0", + "version": "16.0.1.0.2", "category": "Point of Sale", "maintainers": ["legalsylvain"], "author": "GRAP,Odoo Community Association (OCA)", @@ -21,6 +21,7 @@ "pos_customer_comment/static/src/css/pos_customer_comment.scss", "pos_customer_comment/static/src/xml/PartnerDetailsEdit.xml", "pos_customer_comment/static/src/xml/PartnerLine.xml", + "pos_customer_comment/static/src/js/PartnerDetailsEdit.esm.js", ], "web.assets_tests": [ "pos_customer_comment/tests/tours/PosCustomerComment.tour.js", diff --git a/pos_customer_comment/readme/CONTRIBUTORS.rst b/pos_customer_comment/readme/CONTRIBUTORS.rst index ae6f43a86d..2618270913 100644 --- a/pos_customer_comment/readme/CONTRIBUTORS.rst +++ b/pos_customer_comment/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * Sylvain LE GAL (https://twitter.com/legalsylvain) +* Juan Carlos Bonilla diff --git a/pos_customer_comment/static/description/index.html b/pos_customer_comment/static/description/index.html index 4744bf687f..46e5f6833e 100644 --- a/pos_customer_comment/static/description/index.html +++ b/pos_customer_comment/static/description/index.html @@ -1,20 +1,20 @@ - + - + Point of Sale - Cashier Comment + + +
+

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”
  • +
+https://raw.githubusercontent.com/OCA/pos/16.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$

+https://raw.githubusercontent.com/OCA/pos/16.0/pos_discount_all/static/description/order_summary.png +

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

+https://raw.githubusercontent.com/OCA/pos/16.0/pos_discount_all/static/description/pos_receipt.png +
+
+

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
  • +
+
+ +
+

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..f9b5570a13 --- /dev/null +++ b/pos_discount_all/static/src/xml/OrderSummary.xml @@ -0,0 +1,29 @@ + + + + + + + +
+ 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..1b18c35969 --- /dev/null +++ b/pos_discount_all/tests/test_module.py @@ -0,0 +1,65 @@ +# 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 + + + + + + + + + + diff --git a/pos_edit_order_line/README.rst b/pos_edit_order_line/README.rst index 61dca0f127..976a844e21 100644 --- a/pos_edit_order_line/README.rst +++ b/pos_edit_order_line/README.rst @@ -2,10 +2,13 @@ POS Edit Order Line =================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:44dde903de0f82d6771fb69606890611023369cf3690d38548eb877a494144cc + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ POS Edit Order Line .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/pos-16-0/pos-16-0-pos_edit_order_line :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/184/16.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/pos&target_branch=16.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module adds a button "Edit order lines" in main POS interface to allow an easier UX for cashier when editing product price, qty and discount. @@ -56,7 +59,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 +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. diff --git a/pos_edit_order_line/__manifest__.py b/pos_edit_order_line/__manifest__.py index caf790b727..ead354b40a 100644 --- a/pos_edit_order_line/__manifest__.py +++ b/pos_edit_order_line/__manifest__.py @@ -5,7 +5,7 @@ { "name": "POS Edit Order Line", - "version": "16.0.1.0.0", + "version": "16.0.1.0.1", "summary": "POS Edit Order Line", "author": "Ooops, Cetmix, Odoo Community Association (OCA)", "contributors": "Cetmix", diff --git a/pos_edit_order_line/i18n/es.po b/pos_edit_order_line/i18n/es.po index 3911f994df..75426247e9 100644 --- a/pos_edit_order_line/i18n/es.po +++ b/pos_edit_order_line/i18n/es.po @@ -6,15 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-03-06 18:23+0000\n" -"Last-Translator: Fernando \n" +"PO-Revision-Date: 2023-08-22 18:15+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.14.1\n" +"X-Generator: Weblate 4.17\n" #. module: pos_edit_order_line #: model:ir.model.fields,field_description:pos_edit_order_line.field_pos_config__allow_edit_order_line @@ -27,6 +27,13 @@ msgstr "Permitir editar ticket" msgid "Allow edit Order Line in popup" msgstr "Permitir editar ticket en un popup" +#. module: pos_edit_order_line +#. odoo-javascript +#: code:addons/pos_edit_order_line/static/src/js/EditOrderPopup.js:0 +#, python-format +msgid "Cancel" +msgstr "Cancelar" + #. module: pos_edit_order_line #: model:ir.model,name:pos_edit_order_line.model_res_config_settings msgid "Config Settings" @@ -86,6 +93,13 @@ msgstr "Producto" msgid "Quantity" msgstr "Cantidad" +#. module: pos_edit_order_line +#. odoo-javascript +#: code:addons/pos_edit_order_line/static/src/js/EditOrderPopup.js:0 +#, python-format +msgid "Save" +msgstr "Guardar" + #. module: pos_edit_order_line #. odoo-javascript #: code:addons/pos_edit_order_line/static/src/xml/EditOrderPopup.xml:0 diff --git a/pos_edit_order_line/i18n/it.po b/pos_edit_order_line/i18n/it.po index b30c8634bc..68c235a3bb 100644 --- a/pos_edit_order_line/i18n/it.po +++ b/pos_edit_order_line/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2023-03-09 00:18+0000\n" +"PO-Revision-Date: 2023-03-30 10:23+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -27,6 +27,13 @@ msgstr "Abilita la modifica righe ordine con popup" msgid "Allow edit Order Line in popup" msgstr "Abilita la modifica righe ordine con popup" +#. module: pos_edit_order_line +#. odoo-javascript +#: code:addons/pos_edit_order_line/static/src/js/EditOrderPopup.js:0 +#, python-format +msgid "Cancel" +msgstr "Annulla" + #. module: pos_edit_order_line #: model:ir.model,name:pos_edit_order_line.model_res_config_settings msgid "Config Settings" @@ -86,6 +93,13 @@ msgstr "Prodotto" msgid "Quantity" msgstr "Quantità" +#. module: pos_edit_order_line +#. odoo-javascript +#: code:addons/pos_edit_order_line/static/src/js/EditOrderPopup.js:0 +#, python-format +msgid "Save" +msgstr "Salva" + #. module: pos_edit_order_line #. odoo-javascript #: code:addons/pos_edit_order_line/static/src/xml/EditOrderPopup.xml:0 diff --git a/pos_edit_order_line/i18n/pos_edit_order_line.pot b/pos_edit_order_line/i18n/pos_edit_order_line.pot index e8f9e6a1e8..e33dd9fb22 100644 --- a/pos_edit_order_line/i18n/pos_edit_order_line.pot +++ b/pos_edit_order_line/i18n/pos_edit_order_line.pot @@ -24,6 +24,13 @@ msgstr "" msgid "Allow edit Order Line in popup" msgstr "" +#. module: pos_edit_order_line +#. odoo-javascript +#: code:addons/pos_edit_order_line/static/src/js/EditOrderPopup.js:0 +#, python-format +msgid "Cancel" +msgstr "" + #. module: pos_edit_order_line #: model:ir.model,name:pos_edit_order_line.model_res_config_settings msgid "Config Settings" @@ -83,6 +90,13 @@ msgstr "" msgid "Quantity" msgstr "" +#. module: pos_edit_order_line +#. odoo-javascript +#: code:addons/pos_edit_order_line/static/src/js/EditOrderPopup.js:0 +#, python-format +msgid "Save" +msgstr "" + #. module: pos_edit_order_line #. odoo-javascript #: code:addons/pos_edit_order_line/static/src/xml/EditOrderPopup.xml:0 diff --git a/pos_edit_order_line/static/description/index.html b/pos_edit_order_line/static/description/index.html index 70829208a0..dd47932ad4 100644 --- a/pos_edit_order_line/static/description/index.html +++ b/pos_edit_order_line/static/description/index.html @@ -1,20 +1,20 @@ - + - + POS Edit Order Line + + +
+

Pos Loyalty Redeem Payment

+ + +

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

+

This module allows gift cards to be applied as a payment method when customer +uses it. Provides the necessary flexibility to accomplish with European +Regulations (Council +Directive (EU) 2016/1065 of 27 June 2016 amending Directive 2006/112/EC).

+

Table of contents

+ +
+

Configuration

+

To allow a loyalty program of type Gift Card to be redeemed as a payment +method, first select Payment Method as Redemption Method:

+Configure a loyalty program to be redeemed as payments +

Then, choose those POS Payment Methods that will be used to redeem cards:

+Select payment methods to be used for card redeeming +

On selected payment methods, field Used for loyalty program has to be checked:

+Payment method used for loyalty program +
+
+

Usage

+

In the payment screen of PoS interface, after selecting configured payment +method a popup requests loyalty card code:

+config +

After entering card code, a new popup asks user to introduce amount to redeem:

+config +

A new payment line is added with selected amount:

+config +

After order is completed, loyalty card report is downloaded with updated +points.

+
+
+

Known issues / Roadmap

+
    +
  • Make popup used for redeeming compatible with Mozilla Firefox. Currently CSS +rules are not applied correctly to it with this navigator
  • +
+
+
+

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

+
    +
  • FactorLibre
  • +
+
+
+

Contributors

+ +
+
+

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.

+

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_loyalty_redeem_payment/static/img/paymentMethod.png b/pos_loyalty_redeem_payment/static/img/paymentMethod.png new file mode 100644 index 0000000000..840a813531 Binary files /dev/null and b/pos_loyalty_redeem_payment/static/img/paymentMethod.png differ diff --git a/pos_loyalty_redeem_payment/static/img/paymentMethodCheck.png b/pos_loyalty_redeem_payment/static/img/paymentMethodCheck.png new file mode 100644 index 0000000000..0ef3af38c9 Binary files /dev/null and b/pos_loyalty_redeem_payment/static/img/paymentMethodCheck.png differ diff --git a/pos_loyalty_redeem_payment/static/img/redeemMethod.png b/pos_loyalty_redeem_payment/static/img/redeemMethod.png new file mode 100644 index 0000000000..470076aef4 Binary files /dev/null and b/pos_loyalty_redeem_payment/static/img/redeemMethod.png differ diff --git a/pos_loyalty_redeem_payment/static/img/usage_1_code_popup.png b/pos_loyalty_redeem_payment/static/img/usage_1_code_popup.png new file mode 100644 index 0000000000..1de6534879 Binary files /dev/null and b/pos_loyalty_redeem_payment/static/img/usage_1_code_popup.png differ diff --git a/pos_loyalty_redeem_payment/static/img/usage_2_amount_popup.png b/pos_loyalty_redeem_payment/static/img/usage_2_amount_popup.png new file mode 100644 index 0000000000..c6802735a3 Binary files /dev/null and b/pos_loyalty_redeem_payment/static/img/usage_2_amount_popup.png differ diff --git a/pos_loyalty_redeem_payment/static/img/usage_3_payment_line.png b/pos_loyalty_redeem_payment/static/img/usage_3_payment_line.png new file mode 100644 index 0000000000..57f62990fc Binary files /dev/null and b/pos_loyalty_redeem_payment/static/img/usage_3_payment_line.png differ diff --git a/pos_loyalty_redeem_payment/static/src/js/PaymentScreen.esm.js b/pos_loyalty_redeem_payment/static/src/js/PaymentScreen.esm.js new file mode 100644 index 0000000000..045464a9b3 --- /dev/null +++ b/pos_loyalty_redeem_payment/static/src/js/PaymentScreen.esm.js @@ -0,0 +1,183 @@ +/** @odoo-module **/ + +import NumberBuffer from "point_of_sale.NumberBuffer"; +import PaymentScreen from "point_of_sale.PaymentScreen"; +import Registries from "point_of_sale.Registries"; +import session from "web.session"; + +export const CouponPosPaymentScreen = (OriginalPaymentScreen) => + class extends OriginalPaymentScreen { + _updateSelectedPaymentline() { + // Disallow payment line editing + if (this.selectedPaymentLine && this.selectedPaymentLine.coupon_data) + return; + super._updateSelectedPaymentline(); + } + + async isValidCode(code, paymentMethod) { + const order = this.env.pos.get_order(); + const customer = order.get_partner(); + return await this.env.services.rpc({ + model: "pos.config", + method: "use_coupon_code", + args: [ + [this.env.pos.config.id], + code, + order.creation_date, + customer ? customer.id : false, + ], + kwargs: { + context: { + from_payment_screen: true, + payment_method_id: paymentMethod.id, + }, + }, + }); + } + + // If voucher code has already been activated, + // we cannot used twice in same or different orders without being processed. + // First we have to process the order and then use it again. + codeIsDuplicated(orders, code) { + return orders.some((order) => + order.paymentlines.some( + (line) => line.coupon_data && line.coupon_data.code === code + ) + ); + } + + hasBeenScanned(code) { + const pending_orders = this.env.pos.get_order_list(); + if (this.codeIsDuplicated(pending_orders, code)) { + this.showNotification( + this.env._t( + "That coupon code has already been scanned and activated. Please, process pending orders." + ), + 5000 + ); + return false; + } + return true; + } + + async insertAndValidateCode(paymentMethod) { + const {confirmed, payload: code} = await this.showPopup("TextInputPopup", { + title: this.env._t("Enter Code"), + startingValue: "", + placeholder: this.env._t("Gift Card"), + }); + if (!confirmed || !this.hasBeenScanned(code)) return 0; + + const trimmedCode = code.trim(); + if (trimmedCode) { + const {successful, payload} = await this.isValidCode( + trimmedCode, + paymentMethod + ); + if (successful) { + return {payload, code}; + } + this.showNotification(payload.error_message, 5000); + } + return 0; + } + + async insertAmountToRedeem(maxVoucherAmount) { + const to_paid = Math.min(maxVoucherAmount, this.currentOrder.get_due()); + const {confirmed, payload: amount} = await this.showPopup( + "ResponsiveNumberPopup", + { + startingValue: 0, + title: _.str.sprintf( + this.env._t("Set amount to redeem, up to %s"), + this.env.pos.format_currency(to_paid) + ), + } + ); + if (confirmed) { + const new_amount = parseFloat(amount.replace(",", ".")); + if (new_amount <= maxVoucherAmount) { + return new_amount; + } + this.showPopup("ErrorPopup", { + body: _.str.sprintf( + this.env._t( + "You tried to redeem %s, but maximum for this gift card in this order is %s" + ), + this.env.pos.format_currency(new_amount), + this.env.pos.format_currency(maxVoucherAmount) + ), + }); + } + return 0; + } + + // Only valid for voucher and gift card programs + async applyProgramAsPaymentMethod(paymentMethod) { + const {payload, code} = await this.insertAndValidateCode(paymentMethod); + if (payload) { + const maxCouponValue = Math.min( + this.currentOrder.get_total_with_tax(), + payload.points + ); + const amount = await this.insertAmountToRedeem(maxCouponValue); + if (amount) { + const newPaymentLine = + this.currentOrder.add_paymentline(paymentMethod); + newPaymentLine.set_amount(amount); + // Amount = amount to redeem + newPaymentLine.coupon_data = {coupon: payload, amount, code}; + newPaymentLine.coupon_id = payload.coupon_id; + if (newPaymentLine) { + NumberBuffer.reset(); + } else { + this.showPopup("ErrorPopup", { + title: this.env._t("Error"), + body: this.env._t( + "There is already an electronic payment in progress." + ), + }); + } + } + } + } + + addNewPaymentLine({detail: paymentMethod}) { + const order = this.currentOrder; + if ( + order.get_due() && + order.get_subtotal() > 0 && + paymentMethod.used_for_loyalty_program + ) { + this.applyProgramAsPaymentMethod(paymentMethod); + return; + } + super.addNewPaymentLine(...arguments); + } + + async _postPushOrderResolve(order, order_server_ids) { + if (order.has_redeem_payment_lines()) { + const payload = await this.rpc({ + model: "pos.order", + method: "get_loy_card_reports_from_order", + args: [order_server_ids], + kwargs: {context: session.user_context}, + }); + if (payload.coupon_report) { + for (const report_entry of Object.entries(payload.coupon_report)) { + await this.env.legacyActionManager.do_action(report_entry[0], { + additional_context: { + active_ids: report_entry[1], + }, + }); + } + } + if (payload.new_coupon_info) { + order.new_coupon_info = payload.new_coupon_info; + } + } + return super._postPushOrderResolve(...arguments); + } + }; + +Registries.Component.extend(PaymentScreen, CouponPosPaymentScreen); diff --git a/pos_loyalty_redeem_payment/static/src/js/ResponsiveNumberPopup.esm.js b/pos_loyalty_redeem_payment/static/src/js/ResponsiveNumberPopup.esm.js new file mode 100644 index 0000000000..a5336af582 --- /dev/null +++ b/pos_loyalty_redeem_payment/static/src/js/ResponsiveNumberPopup.esm.js @@ -0,0 +1,11 @@ +odoo.define("pos_loyalty_partial_redeem.ResponsiveNumberPopup", function (require) { + const NumberPopup = require("point_of_sale.NumberPopup"); + const Registries = require("point_of_sale.Registries"); + + class ResponsiveNumberPopup extends NumberPopup {} + ResponsiveNumberPopup.template = "ResponsiveNumberPopup"; + + Registries.Component.add(ResponsiveNumberPopup); + + return ResponsiveNumberPopup; +}); diff --git a/pos_loyalty_redeem_payment/static/src/js/models.esm.js b/pos_loyalty_redeem_payment/static/src/js/models.esm.js new file mode 100644 index 0000000000..f9a1a63386 --- /dev/null +++ b/pos_loyalty_redeem_payment/static/src/js/models.esm.js @@ -0,0 +1,42 @@ +/** @odoo-module **/ + +import {Order, Payment} from "point_of_sale.models"; +import Registries from "point_of_sale.Registries"; + +export const RedeemPaymentOrder = (OriginalOrder) => + class extends OriginalOrder { + has_redeem_payment_lines() { + return this.paymentlines.some( + (pl) => pl.payment_method.used_for_loyalty_program + ); + } + + wait_for_push_order() { + let result = super.wait_for_push_order(...arguments); + result = Boolean(result || this.has_redeem_payment_lines()); + return result; + } + }; + +Registries.Model.extend(Order, RedeemPaymentOrder); + +export const PosVoucherRedeemPayment = (OriginalPayment) => + class extends OriginalPayment { + constructor(obj, options) { + super(obj, options); + this.coupon_data = this.coupon_data || null; + } + + export_as_JSON() { + const json = super.export_as_JSON(...arguments); + json.coupon_data = this.coupon_data; + return json; + } + + init_from_JSON(json) { + super.init_from_JSON(...arguments); + this.coupon_data = json.coupon_data; + } + }; + +Registries.Model.extend(Payment, PosVoucherRedeemPayment); diff --git a/pos_loyalty_redeem_payment/static/src/scss/responsive_number_popup.scss b/pos_loyalty_redeem_payment/static/src/scss/responsive_number_popup.scss new file mode 100644 index 0000000000..b9845fc5ce --- /dev/null +++ b/pos_loyalty_redeem_payment/static/src/scss/responsive_number_popup.scss @@ -0,0 +1,3 @@ +.popup.popup-number:has(.popup-number-responsive) { + height: auto !important; +} diff --git a/pos_loyalty_redeem_payment/static/src/xml/Chrome.xml b/pos_loyalty_redeem_payment/static/src/xml/Chrome.xml new file mode 100644 index 0000000000..b205c44196 --- /dev/null +++ b/pos_loyalty_redeem_payment/static/src/xml/Chrome.xml @@ -0,0 +1,17 @@ + + + + + + state.notification.duration == 2000 ? 5000 : state.notification.duration + + + + diff --git a/pos_loyalty_redeem_payment/static/src/xml/ResponsiveNumberPopup.xml b/pos_loyalty_redeem_payment/static/src/xml/ResponsiveNumberPopup.xml new file mode 100644 index 0000000000..d91e4ebff8 --- /dev/null +++ b/pos_loyalty_redeem_payment/static/src/xml/ResponsiveNumberPopup.xml @@ -0,0 +1,14 @@ + + + + + +