diff --git a/pos_meal_voucher/README.rst b/pos_meal_voucher/README.rst new file mode 100644 index 0000000000..2ce37fa6ea --- /dev/null +++ b/pos_meal_voucher/README.rst @@ -0,0 +1,180 @@ +============================ +Point Of Sale - Meal Voucher +============================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:3881e082a79362cd653b81271727fd0bd6c817adf05ba5c87fa872bb7602dca5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/16.0/pos_meal_voucher + :alt: OCA/pos +.. |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_meal_voucher + :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=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to handle meal vouchers in the point of sale. + +Meal vouchers are a payment method, available in some countries (France, Belgium, Romania,…) that allows customers to buy food products in grocery stores or pay in restaurants. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Products +~~~~~~~~ + +On a product form, in the "Sales" tab, the "Can be Paid for by Meal Vouchers" checkbox controls whether the product can be paid for by meal vouchers. + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/product_product_form.png + +Product categories can be configured to have a default value for the "Can be Paid for by Meal Vouchers" field for its products. +The "Apply to All Products" button allows to set the value on all products of the category. + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/product_category_form.png + +Point of Sale Payment Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Point of sale payment methods (Point of Sale > Configuration > Payment Methods) have a "Meal Voucher Type" field that defines what type of meal voucher payment method they are: + +* (empty): The payment method is not a meal voucher payment method. +* **Paper**: The payment method will be used when scanning meal voucher barcodes. +* **Electronic**: The payment method will be used for electronic meal vouchers. + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_payment_method_form.png + +Settings +~~~~~~~~ + +This module adds a "Meal Vouchers" section in the point of sale settings (Point of Sale > Configuration > Settings, or Settings > Point of Sale) with several options: + +* **Maximum Amount**: Optional maximum amount per order that can be paid by meal vouchers. Set to 0 to disable. +* **Icon on Order Lines**: Whether to display an icon on point of sale order lines (on the product screen) for products that can be paid for by meal vouchers. +* **Information on Receipt**: Whether to display an asterisk (*) on receipts before each product that can be paid for by meal vouchers as well as the total eligible amount. + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_settings.png + +Usage +===== + +Product Screen +~~~~~~~~~~~~~~ + +On the product screen, the products that can be paid for by meal vouchers are (optionally) identified with an icon and the total amount of those products is displayed. + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_order_screen.png + +Payment Screen +~~~~~~~~~~~~~~ + +On the payment screen, a meal voucher summary is displayed: + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_payment_screen_meal_vouchers.png + +If the received amount is too high, a warning icon is displayed: + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_payment_screen_warning.png + +Receipt +~~~~~~~ + +The receipts can optionally contain information about the products that can be paid for by meal vouchers and the total amount of those products: + +.. figure:: https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/receipt_information.png + +Barcodes +~~~~~~~~ + +A new barcode rule is defined for paper meal vouchers (with 24 characters): + +``...........{NNNDD}........`` + +If you scan the following barcode: ``052566641320080017000000``, a new payment line with an amount of ¤8.00 (``00800``) will be added. + +Known issues / Roadmap +====================== + +Possible Features +~~~~~~~~~~~~~~~~~ + +* Introduce the Meal Voucher Issuer model. +* Deduce the issuer when scanning a meal voucher barcode. +* Add a report to easily compute the total deposit of meal vouchers (per issuer). +* Prevent to scan the same meal voucher barcode twice. + +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 + +Other credits +~~~~~~~~~~~~~ + +The development of this module has been financially supported by: + +* Vracoop (https://portail.vracoop.fr/) +* Demain Supermarché (http://www.demainsupermarche.org/) +* Le Drive tout nu (https://ledrivetoutnu.com/) + +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_meal_voucher/__init__.py b/pos_meal_voucher/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/pos_meal_voucher/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pos_meal_voucher/__manifest__.py b/pos_meal_voucher/__manifest__.py new file mode 100644 index 0000000000..7738fb9fd9 --- /dev/null +++ b/pos_meal_voucher/__manifest__.py @@ -0,0 +1,35 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Point Of Sale - Meal Voucher", + "summary": "Handle meal vouchers in Point of Sale" + " with eligible amount and max amount", + "version": "16.0.1.0.0", + "category": "Point of Sale", + "author": "GRAP, Odoo Community Association (OCA)", + "maintainers": ["legalsylvain"], + "website": "https://github.com/OCA/pos", + "license": "AGPL-3", + "depends": [ + "point_of_sale", + ], + "data": [ + "data/barcode_rule.xml", + "views/pos_payment_method_view.xml", + "views/res_config_settings_view.xml", + "views/view_product_category.xml", + "views/view_product_template.xml", + ], + "assets": { + "point_of_sale.assets": [ + "pos_meal_voucher/static/src/scss/*.scss", + "pos_meal_voucher/static/src/js/**/*.js", + "pos_meal_voucher/static/src/xml/**/*.xml", + ], + }, + "demo": [ + "demo/product_category.xml", + "demo/product_product.xml", + ], +} diff --git a/pos_meal_voucher/data/barcode_rule.xml b/pos_meal_voucher/data/barcode_rule.xml new file mode 100644 index 0000000000..8cade82ced --- /dev/null +++ b/pos_meal_voucher/data/barcode_rule.xml @@ -0,0 +1,21 @@ + + + + + + Meal Voucher Payment + + meal_voucher_payment + any + 1 + ...........{NNNDD}........ + + + diff --git a/pos_meal_voucher/demo/product_category.xml b/pos_meal_voucher/demo/product_category.xml new file mode 100644 index 0000000000..37c76c7068 --- /dev/null +++ b/pos_meal_voucher/demo/product_category.xml @@ -0,0 +1,15 @@ + + + + + + Food + + + + + diff --git a/pos_meal_voucher/demo/product_product.xml b/pos_meal_voucher/demo/product_product.xml new file mode 100644 index 0000000000..246f21d5e9 --- /dev/null +++ b/pos_meal_voucher/demo/product_product.xml @@ -0,0 +1,17 @@ + + + + + + Organic Wholemeal Bread + + + + 5.30 + + + diff --git a/pos_meal_voucher/i18n/fr.po b/pos_meal_voucher/i18n/fr.po new file mode 100644 index 0000000000..71402d8a7a --- /dev/null +++ b/pos_meal_voucher/i18n/fr.po @@ -0,0 +1,270 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_meal_voucher +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-02-21 17:11+0000\n" +"PO-Revision-Date: 2025-02-21 17:11+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "Maximum Amount" +msgstr "Montant maximum" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_product_category +msgid "Apply to All Products" +msgstr "Appliquer à tous les produits" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_barcode_rule +msgid "Barcode Rule" +msgstr "Règle de code-barres" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_category__meal_voucher_ok +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_product__meal_voucher_ok +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_template__meal_voucher_ok +msgid "Can be Paid for by Meal Vouchers" +msgstr "Peut être payé avec des titres-restaurant" + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_product_product__meal_voucher_ok +#: model:ir.model.fields,help:pos_meal_voucher.field_product_template__meal_voucher_ok +msgid "Check this box if the product can be paid for by meal vouchers." +msgstr "" +"Cocher cette case si le produit peut être payé avec des titres-restaurant." + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_res_config_settings +msgid "Config Settings" +msgstr "Paramètres de configuration" + +#. module: pos_meal_voucher +#: model:ir.model.fields.selection,name:pos_meal_voucher.selection__pos_payment_method__meal_voucher_type__electronic +msgid "Electronic" +msgstr "Électronique" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml:0 +#, python-format +msgid "Eligible Total:" +msgstr "Total éligible :" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__has_meal_voucher_payment_method +msgid "Has Meal Voucher Payment Method" +msgstr "A une méthode de paiement titre-restaurant" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "Icon on Order Lines" +msgstr "Icône sur les lignes de commande" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "" +"If checked, an asterisk (*) will be displayed on receipts before each " +"product that can be paid for by meal vouchers as well as the total eligible " +"amount." +msgstr "" +"Si la case est cochée, une astérisque (*) sera affichée sur les tickets " +"devant chaque produit qui peut être payé avec des titres-restaurant, ainsi " +"que le montant total éligible." + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "" +"If checked, an icon will be displayed on point of sale order lines (on the " +"product screen) for products that can be paid for by meal vouchers." +msgstr "" +"Si la case est cochée, une icône sera affichée sur les lignes de commande " +"(sur l'écran des produits) pour les produits qui peuvent être payés avec des " +"titres-restaurant." + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_product_category__meal_voucher_ok +msgid "" +"If checked, the products of this category will be marked as \"Can be Paid " +"for by Meal Vouchers\" by default." +msgstr "" +"Si la case est cochée, les produits de cette catégorie seront marqués comme " +"\"Peut être payé avec des titres-restaurant\" par défaut." + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "Information on Receipt" +msgstr "Informations sur le ticket" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/js/models.esm.js:0 +#, python-format +msgid "Invalid Meal Voucher" +msgstr "Titre-restaurant invalide" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#, python-format +msgid "Max Amount" +msgstr "Montant maximum" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__enable_meal_voucher_order_lines_icon +#: model:ir.model.fields,field_description:pos_meal_voucher.field_res_config_settings__pos_enable_meal_voucher_order_lines_icon +msgid "Meal Voucher Icon on Order Lines" +msgstr "Icône de titre-restaurant sur lignes de commande" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__enable_meal_voucher_receipt_info +#: model:ir.model.fields,field_description:pos_meal_voucher.field_res_config_settings__pos_enable_meal_voucher_receipt_info +msgid "Meal Voucher Information on Receipt" +msgstr "Informations de titres-restaurant sur le ticket" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__max_meal_voucher_amount +#: model:ir.model.fields,field_description:pos_meal_voucher.field_res_config_settings__pos_max_meal_voucher_amount +msgid "Meal Voucher Maximum Amount" +msgstr "Montant maximum en titres-restaurant" + +#. module: pos_meal_voucher +#: model:ir.model.fields.selection,name:pos_meal_voucher.selection__barcode_rule__type__meal_voucher_payment +msgid "Meal Voucher Payment" +msgstr "Paiement en titres-restaurant" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_payment_method__meal_voucher_type +msgid "Meal Voucher Type" +msgstr "Type de titre-restaurant" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ProductScreen/OrderSummary.xml:0 +#, python-format +msgid "Meal Voucher:" +msgstr "Titre-restaurant :" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +#, python-format +msgid "Meal Vouchers" +msgstr "Titres-restaurant" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml:0 +#, python-format +msgid "Non-Eligible Total:" +msgstr "Total non-éligible :" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "" +"Optional maximum amount per order that can be paid by meal vouchers.\n" +" Set to 0 to disable." +msgstr "" +"Montant maximum en titres-restaurant par vente.\n" +" Mettre à 0 pour désactiver." + +#. module: pos_meal_voucher +#: model:product.template,name:pos_meal_voucher.bread_product_template +msgid "Organic Wholemeal Bread" +msgstr "Pain complet biologique" + +#. module: pos_meal_voucher +#: model:ir.model.fields.selection,name:pos_meal_voucher.selection__pos_payment_method__meal_voucher_type__paper +msgid "Paper" +msgstr "Papier" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_config +msgid "Point of Sale Configuration" +msgstr "Configuration du point de vente" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_order +msgid "Point of Sale Orders" +msgstr "Commandes du point de vente" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_payment_method +msgid "Point of Sale Payment Methods" +msgstr "Modes de paiement du point de vente" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_session +msgid "Point of Sale Session" +msgstr "Session du point de vente" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_template +msgid "Product" +msgstr "Produit" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_category +msgid "Product Category" +msgstr "Catégorie de produit" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_product +msgid "Product Variant" +msgstr "Variante de produit" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml:0 +#, python-format +msgid "Products marked with an asterisk (*) can be paid for by meal vouchers." +msgstr "" +"Les produits marqués d'une astérisque (*) peuvent être payés avec des titres-" +"restaurant." + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_product_category +msgid "" +"Set the above \"Can be Paid for by Meal Vouchers\" value on all of the " +"products of this category" +msgstr "" +"Applique la valeur de \"Peut être payé avec des titres-restaurant\" ci-" +"dessus à tous les produits de cette catégorie" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/js/models.esm.js:0 +#, python-format +msgid "The paper meal voucher with code \"%s\" has already been scanned." +msgstr "Le titre-restaurant papier avec le code \"%s\" a déjà été scanné." + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#, python-format +msgid "Total Eligible" +msgstr "Total éligible" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#, python-format +msgid "Total Received" +msgstr "Total encaissé" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_barcode_rule__type +msgid "Type" +msgstr "Type" diff --git a/pos_meal_voucher/i18n/it.po b/pos_meal_voucher/i18n/it.po new file mode 100644 index 0000000000..89b50056eb --- /dev/null +++ b/pos_meal_voucher/i18n/it.po @@ -0,0 +1,337 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_meal_voucher +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-21 13:36+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_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:35 +#, python-format +msgid "(Dematerialized)" +msgstr "(Dematerializzato)" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "Meal Voucher Amount" +msgstr "Importo buoni pasto" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "Alias" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_product_category +msgid "Apply to all Products" +msgstr "Applicare a tutti i prodotti" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_barcode_rule +msgid "Barcode Rule" +msgstr "Regola codice a barre" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Cashier" +msgstr "Cassiere" + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_product_product__meal_voucher_ok +#: model:ir.model.fields,help:pos_meal_voucher.field_product_template__meal_voucher_ok +msgid "Check this box if the product can be paid with meal vouchers." +msgstr "" +"Selezionare questo campo se il prodotto può essere pagato con buoni pasto." + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "Client" + +#. module: pos_meal_voucher +#: selection:account.journal,meal_voucher_type:0 +msgid "Credit Card / Dematerialized" +msgstr "Carta di credito / dematerializzato" + +#. module: pos_meal_voucher +#: selection:account.journal,meal_voucher_type:0 +msgid "Dematerialized" +msgstr "Dematerializzato" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Discounted Product" +msgstr "Prodotto scontato" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__meal_voucher_display_info_ticket +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "Display Information on Ticket" +msgstr "Visualizza informazioni sul biglietto" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__meal_voucher_display_product_screen +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "Display icon before products on screen" +msgstr "Mostrare l'icona prima dei prodotti a schermo" + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:100 +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:118 +#, python-format +msgid "Eligible Total:" +msgstr "Totale ammissibile:" + +#. module: pos_meal_voucher +#: model:product.category,name:pos_meal_voucher.food_category +msgid "Food" +msgstr "Cibo" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__has_meal_voucher_journal +msgid "Has Meal Voucher Journal" +msgstr "Ha registro buoni pasto" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "" +"If checked, a star (*) will be displayed on the ticket, before each product " +"that can be paid with meal vouchers, and the total of the eligible product " +"will be printed." +msgstr "" +"Se selezionata, un asterisco (*) verrà visualizzato sul biglietto, prima di " +"ogni prodotto che può essere pagato con i buoni pasto, e verrà stampato il " +"totale del prodotto consentito." + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "" +"If checked, an icon will be displayed on the screen, before each product " +"that can be paid with meal vouchers." +msgstr "" +"Se selezionato, un'icona verrà mostrata a schermo, prima di ogni prodotto " +"che può essere pagato con buoni pasto." + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_product_category__meal_voucher_ok +msgid "" +"If checked, the products that belong to the category will be marked as 'can " +"be paid with meal vouchers', by default." +msgstr "" +"Se selezionato, i prodotti che appartengono alla categoria verranno " +"impostati come 'può essere pagato con buoni pasto', di default." + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_account_journal +msgid "Journal" +msgstr "Registro" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "Ubicazione" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "Lotto" + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:59 +#, python-format +msgid "Max Amount" +msgstr "Importo massimo" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "" +"Maximum amount of Meal Vouchers that can be received for a PoS Order.\n" +" Let 0, if you don't want to enable this " +"check." +msgstr "" +"Massimo importo di buoni pasto che può essere ricevuto per un ordine POS.\n" +" Lasciare 0, se non si vuole abilitare questo " +"controllo." + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:46 +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_category__meal_voucher_ok +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_product__meal_voucher_ok +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_template__meal_voucher_ok +#, python-format +msgid "Meal Voucher" +msgstr "Buoni pasto" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__max_meal_voucher_amount +msgid "Meal Voucher Amount" +msgstr "Importo buoni pasto" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Meal Voucher Payment" +msgstr "Pagamento buoni pasto" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_account_bank_statement_import_journal_creation__meal_voucher_type +#: model:ir.model.fields,field_description:pos_meal_voucher.field_account_journal__meal_voucher_type +msgid "Meal Voucher Type" +msgstr "Tipo buoni pasto" + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:19 +#, python-format +msgid "Meal Voucher:" +msgstr "Buoni pasto:" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_pos_config_form +msgid "Meal Vouchers" +msgstr "Buoni pasto" + +#. module: pos_meal_voucher +#: model:product.product,name:pos_meal_voucher.bread +#: model:product.template,name:pos_meal_voucher.bread_product_template +msgid "Organic Wholemeal Bread" +msgstr "Pane integrale biologico" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "Collo" + +#. module: pos_meal_voucher +#: selection:account.journal,meal_voucher_type:0 +msgid "Paper" +msgstr "Carta" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_config +msgid "Point of Sale Configuration" +msgstr "Configurazione punto vendita" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_order +msgid "Point of Sale Orders" +msgstr "Ordini punto vendita" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Priced Product" +msgstr "Prodotto prezzato" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Priced Product (Computed Weight)" +msgstr "Prodotto prezzato (peso calcolato)" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_product +msgid "Product" +msgstr "Prodotto" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_category +msgid "Product Category" +msgstr "Categoria prodotto" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_template +msgid "Product Template" +msgstr "Modello prodotto" + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:96 +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:114 +#, python-format +msgid "Products marked with a star (*) are eligible for Meal vouchers." +msgstr "" +"I prodotti segnalati da un asterisco (*) sono pagabili con i buoni pasto." + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Tare" +msgstr "Tara" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_account_bank_statement_import_journal_creation__meal_voucher_mixed_text +#: model:ir.model.fields,field_description:pos_meal_voucher.field_account_journal__meal_voucher_mixed_text +msgid "Text for Mixed journal" +msgstr "Testo per il registro misto" + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_account_bank_statement_import_journal_creation__meal_voucher_mixed_text +#: model:ir.model.fields,help:pos_meal_voucher.field_account_journal__meal_voucher_mixed_text +msgid "" +"Text that will be displayed in the point of sale if the journal is a mixed " +"journal (Credit Card / Dematerialized) for the dematerialized button." +msgstr "" +"Testo che verrà mostrato nel punto vendita se il registro è misto (carta di " +"credito / dematerializzato) per il pulsante dematerializzato." + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:51 +#, python-format +msgid "Total Eligible" +msgstr "Totale idoneo" + +#. module: pos_meal_voucher +#. openerp-web +#: code:addons/pos_meal_voucher/static/src/xml/pos_meal_voucher.xml:67 +#, python-format +msgid "Total Received" +msgstr "Totale ricevuto" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_barcode_rule__type +msgid "Type" +msgstr "Tipo" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "Prodotto unitario" + +#. module: pos_meal_voucher +#: model:product.product,uom_name:pos_meal_voucher.bread +#: model:product.template,uom_name:pos_meal_voucher.bread_product_template +msgid "Unit(s)" +msgstr "Unità" + +#. module: pos_meal_voucher +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "Prodotto pesato" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_product_category +msgid "" +"by clicking on this button, all the products of this category will have the " +"same settings than the current category, for the value 'Meal Voucher'" +msgstr "" +"cliccando questo pulsante, tutti i prodotti di questa categoria avranno le " +"stesse impostazioni della categoria corrente, per il valore 'buoni pasto'" + +#. module: pos_meal_voucher +#: model:product.product,weight_uom_name:pos_meal_voucher.bread +#: model:product.template,weight_uom_name:pos_meal_voucher.bread_product_template +msgid "kg" +msgstr "kg" diff --git a/pos_meal_voucher/i18n/pos_meal_voucher.pot b/pos_meal_voucher/i18n/pos_meal_voucher.pot new file mode 100644 index 0000000000..bab52b1ffb --- /dev/null +++ b/pos_meal_voucher/i18n/pos_meal_voucher.pot @@ -0,0 +1,252 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_meal_voucher +# +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_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "Maximum Amount" +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_product_category +msgid "Apply to All Products" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_barcode_rule +msgid "Barcode Rule" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_category__meal_voucher_ok +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_product__meal_voucher_ok +#: model:ir.model.fields,field_description:pos_meal_voucher.field_product_template__meal_voucher_ok +msgid "Can be Paid for by Meal Vouchers" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_product_product__meal_voucher_ok +#: model:ir.model.fields,help:pos_meal_voucher.field_product_template__meal_voucher_ok +msgid "Check this box if the product can be paid for by meal vouchers." +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields.selection,name:pos_meal_voucher.selection__pos_payment_method__meal_voucher_type__electronic +msgid "Electronic" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml:0 +#, python-format +msgid "Eligible Total:" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__has_meal_voucher_payment_method +msgid "Has Meal Voucher Payment Method" +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "Icon on Order Lines" +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "" +"If checked, an asterisk (*) will be displayed on receipts before each " +"product that can be paid for by meal vouchers as well as the total eligible " +"amount." +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "" +"If checked, an icon will be displayed on point of sale order lines (on the " +"product screen) for products that can be paid for by meal vouchers." +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,help:pos_meal_voucher.field_product_category__meal_voucher_ok +msgid "" +"If checked, the products of this category will be marked as \"Can be Paid " +"for by Meal Vouchers\" by default." +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "Information on Receipt" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/js/models.esm.js:0 +#, python-format +msgid "Invalid Meal Voucher" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#, python-format +msgid "Max Amount" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__enable_meal_voucher_order_lines_icon +#: model:ir.model.fields,field_description:pos_meal_voucher.field_res_config_settings__pos_enable_meal_voucher_order_lines_icon +msgid "Meal Voucher Icon on Order Lines" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__enable_meal_voucher_receipt_info +#: model:ir.model.fields,field_description:pos_meal_voucher.field_res_config_settings__pos_enable_meal_voucher_receipt_info +msgid "Meal Voucher Information on Receipt" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_config__max_meal_voucher_amount +#: model:ir.model.fields,field_description:pos_meal_voucher.field_res_config_settings__pos_max_meal_voucher_amount +msgid "Meal Voucher Maximum Amount" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields.selection,name:pos_meal_voucher.selection__barcode_rule__type__meal_voucher_payment +msgid "Meal Voucher Payment" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_pos_payment_method__meal_voucher_type +msgid "Meal Voucher Type" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ProductScreen/OrderSummary.xml:0 +#, python-format +msgid "Meal Voucher:" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +#, python-format +msgid "Meal Vouchers" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml:0 +#, python-format +msgid "Non-Eligible Total:" +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.res_config_settings_view_form +msgid "" +"Optional maximum amount per order that can be paid by meal vouchers.\n" +" Set to 0 to disable." +msgstr "" + +#. module: pos_meal_voucher +#: model:product.template,name:pos_meal_voucher.bread_product_template +msgid "Organic Wholemeal Bread" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields.selection,name:pos_meal_voucher.selection__pos_payment_method__meal_voucher_type__paper +msgid "Paper" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_config +msgid "Point of Sale Configuration" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_order +msgid "Point of Sale Orders" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_payment_method +msgid "Point of Sale Payment Methods" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_pos_session +msgid "Point of Sale Session" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_template +msgid "Product" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_category +msgid "Product Category" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model,name:pos_meal_voucher.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml:0 +#, python-format +msgid "Products marked with an asterisk (*) can be paid for by meal vouchers." +msgstr "" + +#. module: pos_meal_voucher +#: model_terms:ir.ui.view,arch_db:pos_meal_voucher.view_product_category +msgid "" +"Set the above \"Can be Paid for by Meal Vouchers\" value on all of the " +"products of this category" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/js/models.esm.js:0 +#, python-format +msgid "The paper meal voucher with code \"%s\" has already been scanned." +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#, python-format +msgid "Total Eligible" +msgstr "" + +#. module: pos_meal_voucher +#. odoo-javascript +#: code:addons/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml:0 +#, python-format +msgid "Total Received" +msgstr "" + +#. module: pos_meal_voucher +#: model:ir.model.fields,field_description:pos_meal_voucher.field_barcode_rule__type +msgid "Type" +msgstr "" diff --git a/pos_meal_voucher/models/__init__.py b/pos_meal_voucher/models/__init__.py new file mode 100644 index 0000000000..ef43dffb81 --- /dev/null +++ b/pos_meal_voucher/models/__init__.py @@ -0,0 +1,9 @@ +from . import barcode_rule +from . import pos_config +from . import pos_order +from . import pos_payment_method +from . import pos_session +from . import product_category +from . import product_product +from . import product_template +from . import res_config_settings diff --git a/pos_meal_voucher/models/barcode_rule.py b/pos_meal_voucher/models/barcode_rule.py new file mode 100644 index 0000000000..9fb259de6f --- /dev/null +++ b/pos_meal_voucher/models/barcode_rule.py @@ -0,0 +1,14 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class BarcodeRule(models.Model): + _inherit = "barcode.rule" + + type = fields.Selection( + selection_add=[("meal_voucher_payment", "Meal Voucher Payment")], + ondelete={"meal_voucher_payment": "set default"}, + ) diff --git a/pos_meal_voucher/models/pos_config.py b/pos_meal_voucher/models/pos_config.py new file mode 100644 index 0000000000..b2b0ed1f66 --- /dev/null +++ b/pos_meal_voucher/models/pos_config.py @@ -0,0 +1,31 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class PosConfig(models.Model): + _inherit = "pos.config" + + max_meal_voucher_amount = fields.Monetary( + string="Meal Voucher Maximum Amount", + currency_field="currency_id", + ) + enable_meal_voucher_order_lines_icon = fields.Boolean( + string="Meal Voucher Icon on Order Lines", default=True + ) + enable_meal_voucher_receipt_info = fields.Boolean( + string="Meal Voucher Information on Receipt", + ) + has_meal_voucher_payment_method = fields.Boolean( + compute="_compute_has_meal_voucher_payment_method" + ) + + def _compute_has_meal_voucher_payment_method(self): + for config in self: + config.has_meal_voucher_payment_method = bool( + config.payment_method_ids.filtered( + lambda x: x.meal_voucher_type is not False + ) + ) diff --git a/pos_meal_voucher/models/pos_order.py b/pos_meal_voucher/models/pos_order.py new file mode 100644 index 0000000000..e904098ef1 --- /dev/null +++ b/pos_meal_voucher/models/pos_order.py @@ -0,0 +1,17 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class PosOrder(models.Model): + _inherit = "pos.order" + + def _payment_fields(self, order, ui_paymentline): + res = super()._payment_fields(order, ui_paymentline) + # the pos.payment.name field is named "Label" and is not used for + # normal payments, so it is used here to store the payment note (the + # barcode of paper meal vouchers). + res["name"] = ui_paymentline.get("payment_note", False) + return res diff --git a/pos_meal_voucher/models/pos_payment_method.py b/pos_meal_voucher/models/pos_payment_method.py new file mode 100644 index 0000000000..c1a81c9550 --- /dev/null +++ b/pos_meal_voucher/models/pos_payment_method.py @@ -0,0 +1,16 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class PosPaymentMethod(models.Model): + _inherit = "pos.payment.method" + + meal_voucher_type = fields.Selection( + selection=[ + ("paper", "Paper"), + ("electronic", "Electronic"), + ], + ) diff --git a/pos_meal_voucher/models/pos_session.py b/pos_meal_voucher/models/pos_session.py new file mode 100644 index 0000000000..96b0292705 --- /dev/null +++ b/pos_meal_voucher/models/pos_session.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2025 Coop IT Easy SC +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +from odoo import models + + +class PosSession(models.Model): + _inherit = "pos.session" + + def _loader_params_pos_payment_method(self): + res = super()._loader_params_pos_payment_method() + res["search_params"]["fields"].append("meal_voucher_type") + return res + + def _loader_params_product_product(self): + res = super()._loader_params_product_product() + res["search_params"]["fields"].append("meal_voucher_ok") + return res diff --git a/pos_meal_voucher/models/product_category.py b/pos_meal_voucher/models/product_category.py new file mode 100644 index 0000000000..6761f84e31 --- /dev/null +++ b/pos_meal_voucher/models/product_category.py @@ -0,0 +1,25 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + meal_voucher_ok = fields.Boolean( + string="Can be Paid for by Meal Vouchers", + help="If checked, the products of this category will be marked as " + '"Can be Paid for by Meal Vouchers" by default.', + ) + + def button_apply_meal_voucher_settings(self): + ProductTemplate = self.env["product.template"] + for category in self: + templates = ( + ProductTemplate.sudo() + .with_context(active_test=False) + .search([("categ_id", "=", category.id)]) + ) + templates.write({"meal_voucher_ok": category.meal_voucher_ok}) diff --git a/pos_meal_voucher/models/product_product.py b/pos_meal_voucher/models/product_product.py new file mode 100644 index 0000000000..b6af4c0fcf --- /dev/null +++ b/pos_meal_voucher/models/product_product.py @@ -0,0 +1,14 @@ +# Copyright (C) 2021 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + @api.onchange("categ_id") + def onchange_categ_id_pos_meal_voucher(self): + for product in self: + product.meal_voucher_ok = product.categ_id.meal_voucher_ok diff --git a/pos_meal_voucher/models/product_template.py b/pos_meal_voucher/models/product_template.py new file mode 100644 index 0000000000..c457f376c7 --- /dev/null +++ b/pos_meal_voucher/models/product_template.py @@ -0,0 +1,29 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + meal_voucher_ok = fields.Boolean( + string="Can be Paid for by Meal Vouchers", + help="Check this box if the product can be paid for by meal vouchers.", + ) + + @api.onchange("categ_id") + def onchange_categ_id_pos_meal_voucher(self): + for template in self: + template.meal_voucher_ok = template.categ_id.meal_voucher_ok + + @api.model_create_multi + def create(self, vals_list): + product_category_model = self.env["product.category"] + for vals in vals_list: + if "meal_voucher_ok" not in vals and "categ_id" in vals: + # Guess meal_voucher_ok if not present, based on the category + categ = product_category_model.browse(vals.get("categ_id")) + vals["meal_voucher_ok"] = categ.meal_voucher_ok + return super().create(vals_list) diff --git a/pos_meal_voucher/models/res_config_settings.py b/pos_meal_voucher/models/res_config_settings.py new file mode 100644 index 0000000000..87eafd0149 --- /dev/null +++ b/pos_meal_voucher/models/res_config_settings.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2025 Coop IT Easy SC +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + pos_max_meal_voucher_amount = fields.Monetary( + related="pos_config_id.max_meal_voucher_amount", + readonly=False, + ) + pos_enable_meal_voucher_order_lines_icon = fields.Boolean( + related="pos_config_id.enable_meal_voucher_order_lines_icon", + readonly=False, + ) + pos_enable_meal_voucher_receipt_info = fields.Boolean( + related="pos_config_id.enable_meal_voucher_receipt_info", + readonly=False, + ) diff --git a/pos_meal_voucher/readme/CONFIGURE.rst b/pos_meal_voucher/readme/CONFIGURE.rst new file mode 100644 index 0000000000..42abba35a4 --- /dev/null +++ b/pos_meal_voucher/readme/CONFIGURE.rst @@ -0,0 +1,33 @@ +Products +~~~~~~~~ + +On a product form, in the "Sales" tab, the "Can be Paid for by Meal Vouchers" checkbox controls whether the product can be paid for by meal vouchers. + +.. figure:: ../static/description/product_product_form.png + +Product categories can be configured to have a default value for the "Can be Paid for by Meal Vouchers" field for its products. +The "Apply to All Products" button allows to set the value on all products of the category. + +.. figure:: ../static/description/product_category_form.png + +Point of Sale Payment Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Point of sale payment methods (Point of Sale > Configuration > Payment Methods) have a "Meal Voucher Type" field that defines what type of meal voucher payment method they are: + +* (empty): The payment method is not a meal voucher payment method. +* **Paper**: The payment method will be used when scanning meal voucher barcodes. +* **Electronic**: The payment method will be used for electronic meal vouchers. + +.. figure:: ../static/description/pos_payment_method_form.png + +Settings +~~~~~~~~ + +This module adds a "Meal Vouchers" section in the point of sale settings (Point of Sale > Configuration > Settings, or Settings > Point of Sale) with several options: + +* **Maximum Amount**: Optional maximum amount per order that can be paid by meal vouchers. Set to 0 to disable. +* **Icon on Order Lines**: Whether to display an icon on point of sale order lines (on the product screen) for products that can be paid for by meal vouchers. +* **Information on Receipt**: Whether to display an asterisk (*) on receipts before each product that can be paid for by meal vouchers as well as the total eligible amount. + +.. figure:: ../static/description/pos_settings.png diff --git a/pos_meal_voucher/readme/CONTRIBUTORS.rst b/pos_meal_voucher/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..9f76a75bc1 --- /dev/null +++ b/pos_meal_voucher/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Sylvain LE GAL diff --git a/pos_meal_voucher/readme/CREDITS.rst b/pos_meal_voucher/readme/CREDITS.rst new file mode 100644 index 0000000000..969f293038 --- /dev/null +++ b/pos_meal_voucher/readme/CREDITS.rst @@ -0,0 +1,5 @@ +The development of this module has been financially supported by: + +* Vracoop (https://portail.vracoop.fr/) +* Demain Supermarché (http://www.demainsupermarche.org/) +* Le Drive tout nu (https://ledrivetoutnu.com/) diff --git a/pos_meal_voucher/readme/DESCRIPTION.rst b/pos_meal_voucher/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..e3044761a6 --- /dev/null +++ b/pos_meal_voucher/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module allows to handle meal vouchers in the point of sale. + +Meal vouchers are a payment method, available in some countries (France, Belgium, Romania,…) that allows customers to buy food products in grocery stores or pay in restaurants. diff --git a/pos_meal_voucher/readme/ROADMAP.rst b/pos_meal_voucher/readme/ROADMAP.rst new file mode 100644 index 0000000000..4dbfdf5a6d --- /dev/null +++ b/pos_meal_voucher/readme/ROADMAP.rst @@ -0,0 +1,7 @@ +Possible Features +~~~~~~~~~~~~~~~~~ + +* Introduce the Meal Voucher Issuer model. +* Deduce the issuer when scanning a meal voucher barcode. +* Add a report to easily compute the total deposit of meal vouchers (per issuer). +* Prevent to scan the same meal voucher barcode twice. diff --git a/pos_meal_voucher/readme/USAGE.rst b/pos_meal_voucher/readme/USAGE.rst new file mode 100644 index 0000000000..b46bea9047 --- /dev/null +++ b/pos_meal_voucher/readme/USAGE.rst @@ -0,0 +1,33 @@ +Product Screen +~~~~~~~~~~~~~~ + +On the product screen, the products that can be paid for by meal vouchers are (optionally) identified with an icon and the total amount of those products is displayed. + +.. figure:: ../static/description/pos_order_screen.png + +Payment Screen +~~~~~~~~~~~~~~ + +On the payment screen, a meal voucher summary is displayed: + +.. figure:: ../static/description/pos_payment_screen_meal_vouchers.png + +If the received amount is too high, a warning icon is displayed: + +.. figure:: ../static/description/pos_payment_screen_warning.png + +Receipt +~~~~~~~ + +The receipts can optionally contain information about the products that can be paid for by meal vouchers and the total amount of those products: + +.. figure:: ../static/description/receipt_information.png + +Barcodes +~~~~~~~~ + +A new barcode rule is defined for paper meal vouchers (with 24 characters): + +``...........{NNNDD}........`` + +If you scan the following barcode: ``052566641320080017000000``, a new payment line with an amount of ¤8.00 (``00800``) will be added. diff --git a/pos_meal_voucher/static/description/icon.png b/pos_meal_voucher/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/pos_meal_voucher/static/description/icon.png differ diff --git a/pos_meal_voucher/static/description/index.html b/pos_meal_voucher/static/description/index.html new file mode 100644 index 0000000000..ff314b1f74 --- /dev/null +++ b/pos_meal_voucher/static/description/index.html @@ -0,0 +1,538 @@ + + + + + +Point Of Sale - Meal Voucher + + + +
+

Point Of Sale - Meal Voucher

+ + +

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

+

This module allows to handle meal vouchers in the point of sale.

+

Meal vouchers are a payment method, available in some countries (France, Belgium, Romania,…) that allows customers to buy food products in grocery stores or pay in restaurants.

+

Table of contents

+ +
+

Configuration

+
+

Products

+

On a product form, in the “Sales” tab, the “Can be Paid for by Meal Vouchers” checkbox controls whether the product can be paid for by meal vouchers.

+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/product_product_form.png +
+

Product categories can be configured to have a default value for the “Can be Paid for by Meal Vouchers” field for its products. +The “Apply to All Products” button allows to set the value on all products of the category.

+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/product_category_form.png +
+
+
+

Point of Sale Payment Methods

+

Point of sale payment methods (Point of Sale > Configuration > Payment Methods) have a “Meal Voucher Type” field that defines what type of meal voucher payment method they are:

+
    +
  • (empty): The payment method is not a meal voucher payment method.
  • +
  • Paper: The payment method will be used when scanning meal voucher barcodes.
  • +
  • Electronic: The payment method will be used for electronic meal vouchers.
  • +
+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_payment_method_form.png +
+
+
+

Settings

+

This module adds a “Meal Vouchers” section in the point of sale settings (Point of Sale > Configuration > Settings, or Settings > Point of Sale) with several options:

+
    +
  • Maximum Amount: Optional maximum amount per order that can be paid by meal vouchers. Set to 0 to disable.
  • +
  • Icon on Order Lines: Whether to display an icon on point of sale order lines (on the product screen) for products that can be paid for by meal vouchers.
  • +
  • Information on Receipt: Whether to display an asterisk (*) on receipts before each product that can be paid for by meal vouchers as well as the total eligible amount.
  • +
+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_settings.png +
+
+
+
+

Usage

+
+

Product Screen

+

On the product screen, the products that can be paid for by meal vouchers are (optionally) identified with an icon and the total amount of those products is displayed.

+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_order_screen.png +
+
+
+

Payment Screen

+

On the payment screen, a meal voucher summary is displayed:

+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_payment_screen_meal_vouchers.png +
+

If the received amount is too high, a warning icon is displayed:

+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/pos_payment_screen_warning.png +
+
+
+

Receipt

+

The receipts can optionally contain information about the products that can be paid for by meal vouchers and the total amount of those products:

+
+https://raw.githubusercontent.com/OCA/pos/16.0/pos_meal_voucher/static/description/receipt_information.png +
+
+
+

Barcodes

+

A new barcode rule is defined for paper meal vouchers (with 24 characters):

+

...........{NNNDD}........

+

If you scan the following barcode: 052566641320080017000000, a new payment line with an amount of ¤8.00 (00800) will be added.

+
+
+
+

Known issues / Roadmap

+
+

Possible Features

+
    +
  • Introduce the Meal Voucher Issuer model.
  • +
  • Deduce the issuer when scanning a meal voucher barcode.
  • +
  • Add a report to easily compute the total deposit of meal vouchers (per issuer).
  • +
  • Prevent to scan the same meal voucher barcode twice.
  • +
+
+
+
+

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:

+ +
+
+

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_meal_voucher/static/description/issuer_1_up_dejeuner.jpg b/pos_meal_voucher/static/description/issuer_1_up_dejeuner.jpg new file mode 100644 index 0000000000..a47564c89a Binary files /dev/null and b/pos_meal_voucher/static/description/issuer_1_up_dejeuner.jpg differ diff --git a/pos_meal_voucher/static/description/issuer_2_ticket_restaurant.jpeg b/pos_meal_voucher/static/description/issuer_2_ticket_restaurant.jpeg new file mode 100644 index 0000000000..c8f069e647 Binary files /dev/null and b/pos_meal_voucher/static/description/issuer_2_ticket_restaurant.jpeg differ diff --git a/pos_meal_voucher/static/description/issuer_3_apetiz.png b/pos_meal_voucher/static/description/issuer_3_apetiz.png new file mode 100644 index 0000000000..28617fc922 Binary files /dev/null and b/pos_meal_voucher/static/description/issuer_3_apetiz.png differ diff --git a/pos_meal_voucher/static/description/issuer_4_pass_restaurant.png b/pos_meal_voucher/static/description/issuer_4_pass_restaurant.png new file mode 100644 index 0000000000..f2150b5803 Binary files /dev/null and b/pos_meal_voucher/static/description/issuer_4_pass_restaurant.png differ diff --git a/pos_meal_voucher/static/description/pos_order_screen.png b/pos_meal_voucher/static/description/pos_order_screen.png new file mode 100644 index 0000000000..99b6e4dad8 Binary files /dev/null and b/pos_meal_voucher/static/description/pos_order_screen.png differ diff --git a/pos_meal_voucher/static/description/pos_payment_method_form.png b/pos_meal_voucher/static/description/pos_payment_method_form.png new file mode 100644 index 0000000000..c240e09765 Binary files /dev/null and b/pos_meal_voucher/static/description/pos_payment_method_form.png differ diff --git a/pos_meal_voucher/static/description/pos_payment_screen_meal_vouchers.png b/pos_meal_voucher/static/description/pos_payment_screen_meal_vouchers.png new file mode 100644 index 0000000000..cb35131fdb Binary files /dev/null and b/pos_meal_voucher/static/description/pos_payment_screen_meal_vouchers.png differ diff --git a/pos_meal_voucher/static/description/pos_payment_screen_warning.png b/pos_meal_voucher/static/description/pos_payment_screen_warning.png new file mode 100644 index 0000000000..e787a5f4cf Binary files /dev/null and b/pos_meal_voucher/static/description/pos_payment_screen_warning.png differ diff --git a/pos_meal_voucher/static/description/pos_settings.png b/pos_meal_voucher/static/description/pos_settings.png new file mode 100644 index 0000000000..13e1dee945 Binary files /dev/null and b/pos_meal_voucher/static/description/pos_settings.png differ diff --git a/pos_meal_voucher/static/description/product_category_form.png b/pos_meal_voucher/static/description/product_category_form.png new file mode 100644 index 0000000000..ede32f8d38 Binary files /dev/null and b/pos_meal_voucher/static/description/product_category_form.png differ diff --git a/pos_meal_voucher/static/description/product_product_form.png b/pos_meal_voucher/static/description/product_product_form.png new file mode 100644 index 0000000000..9e7f9cdc41 Binary files /dev/null and b/pos_meal_voucher/static/description/product_product_form.png differ diff --git a/pos_meal_voucher/static/description/receipt_information.png b/pos_meal_voucher/static/description/receipt_information.png new file mode 100644 index 0000000000..b6d0d9a7d4 Binary files /dev/null and b/pos_meal_voucher/static/description/receipt_information.png differ diff --git a/pos_meal_voucher/static/src/js/Screens/PaymentScreen/PaymentScreen.esm.js b/pos_meal_voucher/static/src/js/Screens/PaymentScreen/PaymentScreen.esm.js new file mode 100644 index 0000000000..80ddf841b8 --- /dev/null +++ b/pos_meal_voucher/static/src/js/Screens/PaymentScreen/PaymentScreen.esm.js @@ -0,0 +1,42 @@ +/** @odoo-module **/ +// SPDX-FileCopyrightText: 2025 Coop IT Easy SC +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {Component} from "point_of_sale.Registries"; +import PaymentScreen from "point_of_sale.PaymentScreen"; +import {useBarcodeReader} from "point_of_sale.custom_hooks"; + +const MealVoucherPaymentScreen = (OriginalPaymentScreen) => + class extends OriginalPaymentScreen { + setup() { + super.setup(); + if (this.env.pos.paper_meal_voucher_payment_method !== null) { + useBarcodeReader({ + meal_voucher_payment: this._barcodeMealVoucherAction, + }); + } + } + + async _barcodeMealVoucherAction(code) { + return this.currentOrder.handle_meal_voucher_barcode(code); + } + + get hasMealVoucherPaymentMethod() { + return this.env.pos.config.has_meal_voucher_payment_method; + } + + get mealVoucherEligibleAmount() { + return this.currentOrder.get_total_meal_voucher_eligible(); + } + + get mealVoucherReceivedAmount() { + return this.currentOrder.get_total_meal_voucher_received(); + } + + get maxMealVoucherAmount() { + return this.env.pos.config.max_meal_voucher_amount; + } + }; + +Component.extend(PaymentScreen, MealVoucherPaymentScreen); diff --git a/pos_meal_voucher/static/src/js/Screens/PaymentScreen/PaymentScreenPaymentLines.esm.js b/pos_meal_voucher/static/src/js/Screens/PaymentScreen/PaymentScreenPaymentLines.esm.js new file mode 100644 index 0000000000..595a587765 --- /dev/null +++ b/pos_meal_voucher/static/src/js/Screens/PaymentScreen/PaymentScreenPaymentLines.esm.js @@ -0,0 +1,16 @@ +/** @odoo-module **/ +// SPDX-FileCopyrightText: 2025 Coop IT Easy SC +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {Component} from "point_of_sale.Registries"; +import PaymentScreenPaymentLines from "point_of_sale.PaymentScreenPaymentLines"; + +const MealVoucherPaymentScreenPaymentLines = (OriginalPaymentScreenPaymentLines) => + class extends OriginalPaymentScreenPaymentLines { + isMealVoucher(line) { + return line.payment_method.meal_voucher_type !== false; + } + }; + +Component.extend(PaymentScreenPaymentLines, MealVoucherPaymentScreenPaymentLines); diff --git a/pos_meal_voucher/static/src/js/Screens/ProductScreen/Orderline.esm.js b/pos_meal_voucher/static/src/js/Screens/ProductScreen/Orderline.esm.js new file mode 100644 index 0000000000..6386ed0115 --- /dev/null +++ b/pos_meal_voucher/static/src/js/Screens/ProductScreen/Orderline.esm.js @@ -0,0 +1,19 @@ +/** @odoo-module **/ +// SPDX-FileCopyrightText: 2025 Coop IT Easy SC +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {Component} from "point_of_sale.Registries"; +import Orderline from "point_of_sale.Orderline"; + +const MealVoucherOrderline = (OriginalOrderline) => + class extends OriginalOrderline { + get displayMealVoucherIcon() { + return ( + this.env.pos.config.enable_meal_voucher_order_lines_icon && + this.props.line.get_product().meal_voucher_ok + ); + } + }; + +Component.extend(Orderline, MealVoucherOrderline); diff --git a/pos_meal_voucher/static/src/js/Screens/ProductScreen/ProductScreen.esm.js b/pos_meal_voucher/static/src/js/Screens/ProductScreen/ProductScreen.esm.js new file mode 100644 index 0000000000..3b781122d6 --- /dev/null +++ b/pos_meal_voucher/static/src/js/Screens/ProductScreen/ProductScreen.esm.js @@ -0,0 +1,28 @@ +/** @odoo-module **/ +// SPDX-FileCopyrightText: 2025 Coop IT Easy SC +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +import {Component} from "point_of_sale.Registries"; +import ProductScreen from "point_of_sale.ProductScreen"; +import {useBarcodeReader} from "point_of_sale.custom_hooks"; + +const MealVoucherProductScreen = (OriginalProductScreen) => + class extends OriginalProductScreen { + setup() { + super.setup(); + if (this.env.pos.paper_meal_voucher_payment_method !== null) { + useBarcodeReader({ + meal_voucher_payment: this._barcodeMealVoucherAction, + }); + } + } + + async _barcodeMealVoucherAction(code) { + // Display the payment screen, if it is not the current one. + this.showScreen("PaymentScreen"); + return this.currentOrder.handle_meal_voucher_barcode(code); + } + }; + +Component.extend(ProductScreen, MealVoucherProductScreen); diff --git a/pos_meal_voucher/static/src/js/models.esm.js b/pos_meal_voucher/static/src/js/models.esm.js new file mode 100644 index 0000000000..9b3d25ee98 --- /dev/null +++ b/pos_meal_voucher/static/src/js/models.esm.js @@ -0,0 +1,168 @@ +/** @odoo-module **/ +// Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +// @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import {Order, Orderline, Payment, PosGlobalState} from "point_of_sale.models"; +import {Gui} from "point_of_sale.Gui"; +import {Model} from "point_of_sale.Registries"; +import {_t} from "web.core"; +import {round_precision as round_pr} from "web.utils"; + +const MealVoucherOrder = (OriginalOrder) => + class extends OriginalOrder { + get_total_meal_voucher_eligible() { + return round_pr( + this.orderlines.reduce(function (sum, orderLine) { + if (orderLine.product.meal_voucher_ok) { + return sum + orderLine.get_price_with_tax(); + } + return sum; + }, 0), + this.pos.currency.rounding + ); + } + + get_total_meal_voucher_non_eligible() { + return round_pr( + this.orderlines.reduce(function (sum, orderLine) { + if (!orderLine.product.meal_voucher_ok) { + return sum + orderLine.get_price_with_tax(); + } + return sum; + }, 0), + this.pos.currency.rounding + ); + } + + get_total_meal_voucher_received() { + return round_pr( + this.paymentlines.reduce(function (sum, paymentLine) { + if (paymentLine.is_meal_voucher()) { + return sum + paymentLine.get_amount(); + } + return sum; + }, 0), + this.pos.currency.rounding + ); + } + + async _meal_voucher_is_valid(code) { + for (const payment_line of this.paymentlines) { + if (payment_line.payment_note === code) { + await Gui.showPopup("ErrorPopup", { + title: _t("Invalid Meal Voucher"), + body: _.str.sprintf( + _t( + 'The paper meal voucher with code "%s" has already been scanned.' + ), + code + ), + }); + return false; + } + } + return true; + } + + async handle_meal_voucher_barcode(code) { + if (!(await this._meal_voucher_is_valid(code.code))) { + return; + } + // Add new payment line with the amount found in the barcode. + const payment_line = this.add_paymentline( + this.pos.paper_meal_voucher_payment_method + ); + payment_line.set_amount(code.value); + payment_line.payment_note = code.code; + } + }; + +Model.extend(Order, MealVoucherOrder); + +const RECEIPT_ORDER_LINE_PREFIX = "(*) "; + +const MealVoucherOrderline = (OriginalOrderline) => + class extends OriginalOrderline { + generate_wrapped_product_name() { + if ( + !this.get_product().meal_voucher_ok || + !this.pos.config.enable_meal_voucher_receipt_info + ) { + return super.generate_wrapped_product_name(...arguments); + } + // Temporarily change the product name to add a prefix on the + // receipt. + // + // .generate_wrapped_product_name() calls + // .get_full_product_name(), and it has a different behavior + // depending on whether this.full_product_name is set or not. both + // behaviors must be handled, because one is used when generating + // a receipt during an order, while the order is used when + // retrieving a receipt from a previous order. + // .get_full_product_name() cannot be overridden because its + // result is also used for display in the product screen and + // its result is stored, which would result in the prefix being + // added each time the pos interface is reloaded. + const originalFullProductName = this.full_product_name; + const originalDisplayName = this.product.display_name; + if (originalFullProductName) { + this.full_product_name = + RECEIPT_ORDER_LINE_PREFIX + originalFullProductName; + } else { + this.product.display_name = + RECEIPT_ORDER_LINE_PREFIX + originalDisplayName; + } + const res = super.generate_wrapped_product_name(...arguments); + if (originalFullProductName) { + this.full_product_name = originalFullProductName; + } else { + this.product.display_name = originalDisplayName; + } + return res; + } + }; + +Model.extend(Orderline, MealVoucherOrderline); + +const MealVoucherPayment = (OriginalPayment) => + class extends OriginalPayment { + initialize() { + super.initialize(...arguments); + this.payment_note = null; + } + + init_from_JSON(json) { + super.init_from_JSON(...arguments); + this.payment_note = json.payment_note; + } + + export_as_JSON() { + const res = super.export_as_JSON(...arguments); + res.payment_note = this.payment_note; + return res; + } + + is_meal_voucher() { + return this.payment_method.meal_voucher_type !== false; + } + }; + +Model.extend(Payment, MealVoucherPayment); + +const MealVoucherPosGlobalState = (OriginalPosGlobalState) => + class extends OriginalPosGlobalState { + async load_server_data() { + await super.load_server_data(...arguments); + this.paper_meal_voucher_payment_method = null; + for (const payment_method_id of this.config.payment_method_ids) { + const payment_method = this.payment_methods_by_id[payment_method_id]; + if (payment_method.meal_voucher_type === "paper") { + this.paper_meal_voucher_payment_method = payment_method; + break; + } + } + } + }; + +Model.extend(PosGlobalState, MealVoucherPosGlobalState); diff --git a/pos_meal_voucher/static/src/scss/pos_meal_voucher.scss b/pos_meal_voucher/static/src/scss/pos_meal_voucher.scss new file mode 100644 index 0000000000..33fe07543d --- /dev/null +++ b/pos_meal_voucher/static/src/scss/pos_meal_voucher.scss @@ -0,0 +1,56 @@ +.pos .paymentline .is-meal-voucher { + text-align: center; + padding: map-get($spacers, 3); +} + +.pos .paymentline .is-meal-voucher .fa-cutlery { + border-radius: 8px; + border: 1px solid rgba($gray-700, 0.5); + width: 24px; + line-height: 24px; +} + +.payment-screen div.meal-voucher-summary .fa-warning { + color: red; +} + +.pos .meal-voucher-summary { + // same as .pos .paymentlines + display: flex; + flex-direction: column-reverse; + border-spacing: 0px 10px; + border-collapse: inherit; +} + +.pos .meal-voucher-summary-container { + padding: map-get($spacers, 2) 0; +} + +.pos .meal-voucher-summary-line { + // same as .pos .paymentline, with some changes + display: flex; + flex-grow: 1; + flex-basis: 100%; + background: #fff; + font-size: 16px; + border-top-width: 0px; + padding: map-get($spacers, 2) 0; +} + +.meal-voucher-summary-line .meal-voucher-summary-line-name { + flex-grow: 1; + padding: 0 map-get($spacers, 3); +} + +.meal-voucher-summary-line .meal-voucher-summary-line-amount { + padding: 0 map-get($spacers, 3); +} + +.meal-voucher-summary-line .meal-voucher-summary-line-warning { + font-size: 20px; + margin-bottom: -(map-get($spacers, 2)); +} + +.pos-receipt-meal-voucher-totals { + font-size: 75%; +} diff --git a/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml b/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml new file mode 100644 index 0000000000..9734924cd2 --- /dev/null +++ b/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml @@ -0,0 +1,64 @@ + + + + + +
+

Meal Vouchers

+
+
+
Total Eligible
+
+ +
+
+ +
+
+
+
Max Amount
+
+ +
+
+ +
+
+
+
Total Received
+
+ +
+
+
+
+
+
+ +
diff --git a/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreenPaymentLines.xml b/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreenPaymentLines.xml new file mode 100644 index 0000000000..08f62de9da --- /dev/null +++ b/pos_meal_voucher/static/src/xml/Screens/PaymentScreen/PaymentScreenPaymentLines.xml @@ -0,0 +1,28 @@ + + + + + +
+ +
+
+ +
+ +
+
+
+ +
diff --git a/pos_meal_voucher/static/src/xml/Screens/ProductScreen/OrderSummary.xml b/pos_meal_voucher/static/src/xml/Screens/ProductScreen/OrderSummary.xml new file mode 100644 index 0000000000..8baa8309ae --- /dev/null +++ b/pos_meal_voucher/static/src/xml/Screens/ProductScreen/OrderSummary.xml @@ -0,0 +1,26 @@ + + + + + + +
+
+
+ Meal Voucher: +
+
+
+
+
+
+ +
diff --git a/pos_meal_voucher/static/src/xml/Screens/ProductScreen/Orderline.xml b/pos_meal_voucher/static/src/xml/Screens/ProductScreen/Orderline.xml new file mode 100644 index 0000000000..b80ec3445a --- /dev/null +++ b/pos_meal_voucher/static/src/xml/Screens/ProductScreen/Orderline.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml b/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml new file mode 100644 index 0000000000..cd4cae2e95 --- /dev/null +++ b/pos_meal_voucher/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml @@ -0,0 +1,32 @@ + + + + + + +
+
+ Products marked with an asterisk (*) can be paid for by meal vouchers. +
+ Eligible Total: + +
+ Non-Eligible Total: + +
+
+
+
+ +
diff --git a/pos_meal_voucher/tests/__init__.py b/pos_meal_voucher/tests/__init__.py new file mode 100644 index 0000000000..d9b96c4fa5 --- /dev/null +++ b/pos_meal_voucher/tests/__init__.py @@ -0,0 +1 @@ +from . import test_module diff --git a/pos_meal_voucher/tests/test_module.py b/pos_meal_voucher/tests/test_module.py new file mode 100644 index 0000000000..5d2681f58a --- /dev/null +++ b/pos_meal_voucher/tests/test_module.py @@ -0,0 +1,52 @@ +# Copyright 2021 - Today Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import TransactionCase + + +class TestModule(TransactionCase): + def setUp(self): + super().setUp() + self.ProductProduct = self.env["product.product"] + self.ProductTemplate = self.env["product.template"] + self.food_category = self.env.ref("pos_meal_voucher.food_category") + self.main_category = self.env.ref("product.product_category_all") + self.uom_unit = self.env.ref("uom.product_uom_unit") + + def test_product_product(self): + product = self.ProductProduct.create( + { + "name": "Product", + "uom_id": self.uom_unit.id, + "uom_po_id": self.uom_unit.id, + "categ_id": self.food_category.id, + } + ) + self.assertEqual(product.meal_voucher_ok, True) + + # Affect product to a non-food category and run onchange + product.categ_id = self.main_category.id + product.onchange_categ_id_pos_meal_voucher() + self.assertEqual(product.meal_voucher_ok, False) + + def test_product_template(self): + template = self.ProductTemplate.create( + { + "name": "Product", + "uom_id": self.uom_unit.id, + "uom_po_id": self.uom_unit.id, + "categ_id": self.food_category.id, + } + ) + self.assertEqual(template.meal_voucher_ok, True) + + # Affect template to a non-food category and run onchange + template.categ_id = self.main_category.id + template.onchange_categ_id_pos_meal_voucher() + self.assertEqual(template.meal_voucher_ok, False) + + # Set non-food category as a food category and propagate settings + # to all the child product + self.main_category.meal_voucher_ok = True + self.main_category.button_apply_meal_voucher_settings() + self.assertEqual(template.meal_voucher_ok, True) diff --git a/pos_meal_voucher/views/pos_payment_method_view.xml b/pos_meal_voucher/views/pos_payment_method_view.xml new file mode 100644 index 0000000000..371b97faf8 --- /dev/null +++ b/pos_meal_voucher/views/pos_payment_method_view.xml @@ -0,0 +1,21 @@ + + + + + + pos.payment.method + + + + + + + + + + + diff --git a/pos_meal_voucher/views/res_config_settings_view.xml b/pos_meal_voucher/views/res_config_settings_view.xml new file mode 100644 index 0000000000..477c2119c4 --- /dev/null +++ b/pos_meal_voucher/views/res_config_settings_view.xml @@ -0,0 +1,65 @@ + + + + + + res.config.settings + + + +

Meal Vouchers

+
+
+
+ Maximum Amount +
+ Optional maximum amount per order that can be paid by meal vouchers. + Set to 0 to disable. +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
diff --git a/pos_meal_voucher/views/view_product_category.xml b/pos_meal_voucher/views/view_product_category.xml new file mode 100644 index 0000000000..56d1b7ae6b --- /dev/null +++ b/pos_meal_voucher/views/view_product_category.xml @@ -0,0 +1,27 @@ + + + + + + product.category + + + + +