diff --git a/README.md b/README.md index 79fd0a38b1cb..ecddc84baac0 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,16 @@ addon | version | maintainers | summary --- | --- | --- | --- [account_vat_period_end_statement](account_vat_period_end_statement/) | 16.0.1.2.6 | | Allow to create the 'VAT Statement'. [currency_rate_update_boi](currency_rate_update_boi/) | 16.0.1.0.1 | [![eLBati](https://github.com/eLBati.png?size=30px)](https://github.com/eLBati) | Update exchange rates using www.bancaditalia.it +[fiscal_epos_print](fiscal_epos_print/) | 16.0.1.0.0 | [![eLBati](https://github.com/eLBati.png?size=30px)](https://github.com/eLBati) | ePOS-Print XML Fiscal Printer Driver - Stampanti Epson compatibili: FP81II, FP90III [l10n_it_abicab](l10n_it_abicab/) | 16.0.1.0.1 | [![Borruso](https://github.com/Borruso.png?size=30px)](https://github.com/Borruso) | Base Bank ABI/CAB codes [l10n_it_account](l10n_it_account/) | 16.0.1.1.1 | | Modulo base usato come dipendenza di altri moduli contabili [l10n_it_account_stamp](l10n_it_account_stamp/) | 16.0.1.1.0 | | Gestione automatica dell'imposta di bollo [l10n_it_account_tax_kind](l10n_it_account_tax_kind/) | 16.0.1.0.1 | | Gestione natura delle aliquote IVA [l10n_it_appointment_code](l10n_it_appointment_code/) | 16.0.1.0.0 | | Aggiunge la tabella dei codici carica da usare nelle dichiarazioni fiscali italiane -[l10n_it_asset_management](l10n_it_asset_management/) | 16.0.1.0.1 | | Gestione Cespiti +[l10n_it_asset_management](l10n_it_asset_management/) | 16.0.1.3.0 | | Gestione Cespiti [l10n_it_ateco](l10n_it_ateco/) | 16.0.1.1.1 | | ITA - Codici Ateco [l10n_it_bill_of_entry](l10n_it_bill_of_entry/) | 16.0.1.0.1 | | ITA - Bolle doganali -[l10n_it_central_journal_reportlab](l10n_it_central_journal_reportlab/) | 16.0.1.0.5 | [![MarcoCalcagni](https://github.com/MarcoCalcagni.png?size=30px)](https://github.com/MarcoCalcagni) [![Borruso](https://github.com/Borruso.png?size=30px)](https://github.com/Borruso) | ITA - Libro giornale - Reportlab +[l10n_it_central_journal_reportlab](l10n_it_central_journal_reportlab/) | 16.0.1.0.6 | [![MarcoCalcagni](https://github.com/MarcoCalcagni.png?size=30px)](https://github.com/MarcoCalcagni) [![Borruso](https://github.com/Borruso.png?size=30px)](https://github.com/Borruso) | ITA - Libro giornale - Reportlab [l10n_it_declaration_of_intent](l10n_it_declaration_of_intent/) | 16.0.1.0.11 | | Gestione dichiarazioni di intento [l10n_it_delivery_note](l10n_it_delivery_note/) | 16.0.1.4.5 | [![MarcoCalcagni](https://github.com/MarcoCalcagni.png?size=30px)](https://github.com/MarcoCalcagni) [![aleuffre](https://github.com/aleuffre.png?size=30px)](https://github.com/aleuffre) [![renda-dev](https://github.com/renda-dev.png?size=30px)](https://github.com/renda-dev) | Crea, gestisce e fattura i DDT partendo dalle consegne [l10n_it_delivery_note_base](l10n_it_delivery_note_base/) | 16.0.1.0.2 | [![MarcoCalcagni](https://github.com/MarcoCalcagni.png?size=30px)](https://github.com/MarcoCalcagni) [![Borruso](https://github.com/Borruso.png?size=30px)](https://github.com/Borruso) | Crea e gestisce tabelle principali per gestire i DDT @@ -40,12 +41,12 @@ addon | version | maintainers | summary [l10n_it_fatturapa](l10n_it_fatturapa/) | 16.0.1.3.0 | | Fatture elettroniche [l10n_it_fatturapa_auto_sale_order](l10n_it_fatturapa_auto_sale_order/) | 16.0.1.0.0 | | Automatically set sale orders as related documents [l10n_it_fatturapa_export_zip](l10n_it_fatturapa_export_zip/) | 16.0.1.0.0 | [![sergiocorato](https://github.com/sergiocorato.png?size=30px)](https://github.com/sergiocorato) | Permette di esportare in uno ZIP diversi file XML di fatture elettroniche -[l10n_it_fatturapa_import_zip](l10n_it_fatturapa_import_zip/) | 16.0.1.2.0 | | Permette di importare in uno ZIP diversi file XML di fatture elettroniche +[l10n_it_fatturapa_import_zip](l10n_it_fatturapa_import_zip/) | 16.0.1.3.0 | | Permette di importare in uno ZIP diversi file XML di fatture elettroniche [l10n_it_fatturapa_import_zip_in_rc](l10n_it_fatturapa_import_zip_in_rc/) | 16.0.1.0.0 | [![SirAionTech](https://github.com/SirAionTech.png?size=30px)](https://github.com/SirAionTech) | Importare fatture elettroniche con inversione contabile da un file ZIP. -[l10n_it_fatturapa_in](l10n_it_fatturapa_in/) | 16.0.1.3.0 | | Ricezione fatture elettroniche +[l10n_it_fatturapa_in](l10n_it_fatturapa_in/) | 16.0.1.4.0 | | Ricezione fatture elettroniche [l10n_it_fatturapa_in_purchase](l10n_it_fatturapa_in_purchase/) | 16.0.1.0.0 | | Modulo ponte tra ricezione fatture elettroniche e acquisti [l10n_it_fatturapa_in_rc](l10n_it_fatturapa_in_rc/) | 16.0.1.0.0 | [![sergiocorato](https://github.com/sergiocorato.png?size=30px)](https://github.com/sergiocorato) | Modulo ponte tra e-fattura in acquisto e inversione contabile -[l10n_it_fatturapa_out](l10n_it_fatturapa_out/) | 16.0.1.4.0 | | Emissione fatture elettroniche +[l10n_it_fatturapa_out](l10n_it_fatturapa_out/) | 16.0.1.4.1 | | Emissione fatture elettroniche [l10n_it_fatturapa_out_di](l10n_it_fatturapa_out_di/) | 16.0.1.0.2 | | Dichiarazioni d'intento in fatturapa [l10n_it_fatturapa_out_oss](l10n_it_fatturapa_out_oss/) | 16.0.1.0.2 | | OSS in fatturapa [l10n_it_fatturapa_out_rc](l10n_it_fatturapa_out_rc/) | 16.0.1.0.1 | [![eLBati](https://github.com/eLBati.png?size=30px)](https://github.com/eLBati) | Integrazione l10n_it_fatturapa_out e l10n_it_reverse_charge @@ -62,15 +63,15 @@ addon | version | maintainers | summary [l10n_it_fiscalcode](l10n_it_fiscalcode/) | 16.0.1.0.3 | | ITA - Codice fiscale [l10n_it_fiscalcode_sale](l10n_it_fiscalcode_sale/) | 16.0.1.0.0 | [![eLBati](https://github.com/eLBati.png?size=30px)](https://github.com/eLBati) | Mostra il codice fiscale del cliente nella stampa del preventivo [l10n_it_intrastat](l10n_it_intrastat/) | 16.0.1.1.3 | | Riclassificazione merci e servizi per dichiarazioni Intrastat -[l10n_it_intrastat_statement](l10n_it_intrastat_statement/) | 16.0.1.1.0 | | Dichiarazione Intrastat per l'Agenzia delle Dogane +[l10n_it_intrastat_statement](l10n_it_intrastat_statement/) | 16.0.1.2.0 | | Dichiarazione Intrastat per l'Agenzia delle Dogane [l10n_it_ipa](l10n_it_ipa/) | 16.0.1.0.1 | | ITA - Codice IPA [l10n_it_payment_reason](l10n_it_payment_reason/) | 16.0.1.0.0 | | Aggiunge la tabella delle causali di pagamento da usare ad esempio nelle ritenute d'acconto [l10n_it_pec](l10n_it_pec/) | 16.0.1.0.0 | | Aggiunge il campo email PEC al partner [l10n_it_pos_fiscalcode](l10n_it_pos_fiscalcode/) | 16.0.1.0.0 | [![eLBati](https://github.com/eLBati.png?size=30px)](https://github.com/eLBati) | Gestione codice fiscale del cliente all'interno dell'interfaccia del POS [l10n_it_rea](l10n_it_rea/) | 16.0.1.0.0 | | Gestisce i campi del Repertorio Economico Amministrativo [l10n_it_reverse_charge](l10n_it_reverse_charge/) | 16.0.1.0.4 | | Inversione contabile -[l10n_it_riba](l10n_it_riba/) | 16.0.1.6.3 | | Ricevute bancarie -[l10n_it_sct_cbi](l10n_it_sct_cbi/) | 16.0.1.0.0 | [![SirAionTech](https://github.com/SirAionTech.png?size=30px)](https://github.com/SirAionTech) | Usare gli standard CBI per SEPA Credit Transfer +[l10n_it_riba](l10n_it_riba/) | 16.0.1.7.0 | | Ricevute bancarie +[l10n_it_sct_cbi](l10n_it_sct_cbi/) | 16.0.1.0.1 | [![SirAionTech](https://github.com/SirAionTech.png?size=30px)](https://github.com/SirAionTech) | Usare gli standard CBI per SEPA Credit Transfer [l10n_it_sdi_channel](l10n_it_sdi_channel/) | 16.0.1.1.0 | [![sergiocorato](https://github.com/sergiocorato.png?size=30px)](https://github.com/sergiocorato) | Aggiunge il canale di invio/ricezione dei file XML attraverso lo SdI [l10n_it_split_payment](l10n_it_split_payment/) | 16.0.1.0.0 | | Scissione pagamenti [l10n_it_vat_payability](l10n_it_vat_payability/) | 16.0.1.0.0 | | ITA - Esigibilità IVA diff --git a/fiscal_epos_print/README.rst b/fiscal_epos_print/README.rst new file mode 100644 index 000000000000..66e7342ba751 --- /dev/null +++ b/fiscal_epos_print/README.rst @@ -0,0 +1,150 @@ +============================================================= +ITA - Driver per stampanti fiscali compatibili ePOS-Print XML +============================================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:ba5b8a62de8bec7b038dcedd9f21af3df1eda34c66681317bb8ecd4426015490 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fl10n--italy-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-italy/tree/16.0/fiscal_epos_print + :alt: OCA/l10n-italy +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-italy-16-0/l10n-italy-16-0-fiscal_epos_print + :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/l10n-italy&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +**Italiano** + +Questo modulo permette di stampare gli scontrini del punto vendita, su +stampanti fiscali Epson, tramite protocollo EPos + +Stampanti supportate: + +- FP81II +- FP90III + +**English** + +This module allows to print receipt of point of sale, on fiscal printers +Epson, via EPos protocol. + +Supported printers: + +- FP81II +- FP90III + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +**Italiano** + +- stampare la lista dei reparti della vostra stampante fiscale +- mappare le imposta di vendita di odoo con i gruppi di imposte - + dipartimenti della stampante fiscale, per ogni imposta di vendita in + odoo, usando il campo "Reparto sulla stampante fiscale 1~99" +- in odoo, utilizzare imposte incluse nel prezzo +- connettere la vostra stampante fiscale alla rete locale e recuperare + l'IP +- aprire la configurazione POS e impostare l'indirizzo IP e il seriale + della stampante nella sezione "Stampante Fiscale" +- è tutto, alla validazione del pagamento nella sessione POS, il + sistema stamperà lo scontrino fiscale. + +**English** + +- print list departments of your fiscal printer +- map odoo sale taxes with taxes groups - departments of fiscal + printer, for each sale tax on odoo, using field "Department on fiscal + printer 1~99" +- in odoo, use taxes included in price +- connect your fiscal printer to local network and find IP +- open POS configuration and fill Printer IP Address field +- that's all, at validation of payment on POS session, system prints + fiscal receipt. + +Known issues / Roadmap +====================== + +- Resi: + + - Aggiungere controllo "rendibilità" + - Stampare sullo scontrino un barcode identificativo, in modo da + generare il reso facendone la scansione + +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 +------- + +* Agile Business Group +* Leonardo Donelli +* TAKOBI +* Level Prime Srl + +Contributors +------------ + +- Leonardo Donelli +- `TAKOBI `__: + + - Lorenzo Battistini + +- Alessio Gerace +- Roberto Fichera +- Giuseppe Borruso + +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-eLBati| image:: https://github.com/eLBati.png?size=40px + :target: https://github.com/eLBati + :alt: eLBati + +Current `maintainer `__: + +|maintainer-eLBati| + +This module is part of the `OCA/l10n-italy `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/fiscal_epos_print/__init__.py b/fiscal_epos_print/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/fiscal_epos_print/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/fiscal_epos_print/__manifest__.py b/fiscal_epos_print/__manifest__.py new file mode 100644 index 000000000000..197a3d1ddd3d --- /dev/null +++ b/fiscal_epos_print/__manifest__.py @@ -0,0 +1,64 @@ +# Leonardo Donelli - Creativi Quadrati +# © 2016 Alessio Gerace - Agile Business Group +# © 2018-2020 Lorenzo Battistini +# © 2019-2020 Roberto Fichera - Level Prime Srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "ITA - Driver per stampanti fiscali compatibili ePOS-Print XML", + "version": "16.0.1.0.0", + "category": "Point Of Sale", + "summary": "ePOS-Print XML Fiscal Printer Driver - Stampanti Epson compatibili: " + "FP81II, FP90III", + "author": ( + "Odoo Community Association (OCA), Agile Business Group, " + "Leonardo Donelli, TAKOBI, Level Prime Srl" + ), + "license": "AGPL-3", + "website": "https://github.com/OCA/l10n-italy", + "maintainers": ["eLBati"], + "depends": [ + "point_of_sale", + "hr", + "pos_hr", + # TODO is this necessary? + # 'pos_order_mgmt' + ], + "data": [ + "views/account.xml", + "views/point_of_sale.xml", + "views/employee_view.xml", + ], + "assets": { + "point_of_sale.assets": [ + "fiscal_epos_print/static/lib/pikaday/pikaday.min.css", + "fiscal_epos_print/static/src/css/pos.css", + "fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js", + "fiscal_epos_print/static/lib/pikaday/pikaday.min.js", + "fiscal_epos_print/static/src/js/epson_epos_print.js", + "fiscal_epos_print/static/src/js/models.js", + # ChromeWidgets + "fiscal_epos_print/static/src/js/ChromeWidgets/EpsonEPOSButton.js", + "fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js", + "fiscal_epos_print/static/src/js/ChromeWidgets/SetLotteryCodeButton.js", + "fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js", + # Popups + "fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js", + "fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js", + # Screens + "fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js", + "fiscal_epos_print/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js", + # Popups + "fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml", + "fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml", + # Others + "fiscal_epos_print/static/src/xml/Chrome.xml", + "fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml", + "fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml", + "fiscal_epos_print/static/src/xml/ChromeWidgets/SetLotteryCodeButton.xml", + "fiscal_epos_print/static/src/xml/ChromeWidgets/SetRefundInfoButton.xml", + ], + }, + "installable": True, + "auto_install": False, +} diff --git a/fiscal_epos_print/i18n/fiscal_epos_print.pot b/fiscal_epos_print/i18n/fiscal_epos_print.pot new file mode 100644 index 000000000000..3fa9f73138bc --- /dev/null +++ b/fiscal_epos_print/i18n/fiscal_epos_print.pot @@ -0,0 +1,1008 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fiscal_epos_print +# +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: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/pos_order_mgmt.js:0 +#, python-format +msgid ": order already has a fiscal number, " +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "Fiscal Printer Serial" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "Printer address" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "An error happened while sending data to the printer. Error code: " +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "Apply" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_hr_employee_base +msgid "Basic Employee" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js:0 +#: code:addons/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js:0 +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "Cancel" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__0 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__0 +msgid "Cash" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "CashDrawer Opened" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__1 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__1 +msgid "Cheque" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Close" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Closing Seq." +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Closure Report Z (Fiscal)" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_report +msgid "Closure reference" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js:0 +#, python-format +msgid "Confirm ?" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Confirm Printer Daily Financial Report (Report X)?" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Confirm Printer Fiscal Closure (Report Z)?" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/pos_order_mgmt.js:0 +#, python-format +msgid "Connecting to the fiscal printer" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Connection to the printer failed" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__2 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__2 +msgid "Credit or Credit Card" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_printer_debug_info +msgid "Debug info" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-python +#: code:addons/fiscal_epos_print/models/account.py:0 +#, python-format +msgid "Department ID number range [1 - 99]" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_tax__fpdeptax +msgid "Department on fiscal printer 1~99" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Discount" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__6 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__6 +msgid "Discount on payment" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_doc_num +msgid "Document Number" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_index +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_index +msgid "Electronic Payment / Ticket Index" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_hr_employee +msgid "Employee" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Epson ePOS" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml:0 +#, python-format +msgid "Epson ePOS Operation" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js:0 +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "Error" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Error Message: " +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Error on last ESC/POS command with Fiscal/Non fiscal closed" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Error on last ESC/POS command with Non fiscal open" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Files waiting to be sent: " +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Financial Report X" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Finished" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_operator_number +msgid "Fiscal Operator" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__fiscal_cashdrawer +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__fiscal_cashdrawer +msgid "Fiscal Printer Open CashDrawer" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee__fiscal_operator_number +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__fiscal_operator_number +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_public__fiscal_operator_number +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_users__fiscal_operator_number +msgid "Fiscal Printer Operator" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__fiscal_printer_serial +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_printer_serial +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__fiscal_printer_serial +msgid "Fiscal Printer Serial" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Fiscal closure" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_z_rep_number +msgid "Fiscal closure number" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Fiscal document open" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Fiscal open" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "Fiscal printer" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_receipt_amount +msgid "Fiscal receipt amount" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_receipt_date +msgid "Fiscal receipt date" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_receipt_number +msgid "Fiscal receipt number" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "From other measurement device" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_full_refund +#, python-format +msgid "Full Refund" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__has_message +msgid "Has Message" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "IRA files" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "IRA status" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Invoice recorded" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_account_journal +msgid "Journal" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "Lottery" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetLotteryCodeButton.js:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/SetLotteryCodeButton.xml:0 +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__lottery_code +#, python-format +msgid "Lottery Code" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "Manca iva su prodotto" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Max 4 numbers" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_ids +msgid "Messages" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js:0 +#, python-format +msgid "Must select a refund order before clicking on this button!" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Negative receipt" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "Network error" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__5 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__5 +msgid "No Paid" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "No taxes found" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Non fiscal open" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Offline (end of paper or open cover)" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js:0 +#: code:addons/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js:0 +#, python-format +msgid "Ok" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Old files: " +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Open CashDrawer" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Operations" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/pos_order_mgmt.js:0 +#, python-format +msgid "Order already printed" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Paper running low" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Payment" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Payment in progress" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_type +msgid "Payment type" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Please confirm to execute the Printer Daily Financial Report" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Please confirm to execute the Printer Fiscal Closure" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Please confirm to reprint the last receipt" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_config +msgid "Point of Sale Configuration" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_order +msgid "Point of Sale Orders" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_payment_method +msgid "Point of Sale Payment Methods" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_payment +msgid "Point of Sale Payments" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_session +msgid "Point of Sale Session" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Previous" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__printer_ip +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__printer_ip +msgid "Printer IP Address" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Printer can not be reached" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Printing error" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "" +"Product prices on receipts must be set to 'Tax-Included Price' in POS " +"configuration" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "RT Serial" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "RT data" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "Receipt" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Receipt Date" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Receipt Num." +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Receipt sent to the printer" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_cash_fiscal_serial +msgid "Refund Cash Serial" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/SetRefundInfoButton.xml:0 +#, python-format +msgid "Refund Data" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "Refund Info" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js:0 +#, python-format +msgid "Refund Information Details" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "Refund Information Not Present" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_date +msgid "Refund date reference" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Refund: " +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Rejected files: " +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Reports" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Reprint Last Receipt" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Reprint Last Receipt?" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Reprint last receipt" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Retry" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/SetReprintButton.xml:0 +#, python-format +msgid "Ristampa Ultimo Scontrino" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetReprintButton.js:0 +#, python-format +msgid "Ristampa ultimo scontrino?" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Rounding" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Running low" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Send fiscal X report to the fiscal printer" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Send fiscal closure command to the fiscal printer" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_index +#: model:ir.model.fields,help:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_index +msgid "Set the index of the given payment type to specify the detail." +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__show_receipt_when_printing +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__show_receipt_when_printing +msgid "Show receipt on screen when printing" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "Some fields are empty." +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Status of files to be sent to IRA" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "SubTotal" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_account_tax +msgid "Tax" +msgstr "" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_apos_payment_method_form_fp90 +msgid "Termini pagamento stampante" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_pos_config__printer_ip +#: model:ir.model.fields,help:fiscal_epos_print.field_res_config_settings__printer_ip +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "The hostname or IP address of the fiscal printer" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type +#: model:ir.model.fields,help:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_type +msgid "The payment type to send to the Fiscal Printer." +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "" +"The refund information aren't present. Please insert them before printing " +"the receipt" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__3 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__3 +msgid "Ticket" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__4 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__4 +msgid "Ticket with number" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Title closed" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Title open" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "To format" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__use_https +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__use_https +msgid "Use https" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_res_users +msgid "User" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Waiting for receipt closing in JAVAPOS mode" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Wrong answer" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "Wrong tax configuration" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "XXXXXXXX" +msgstr "" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "YYYY-MM-DD" +msgstr "" diff --git a/fiscal_epos_print/i18n/it.po b/fiscal_epos_print/i18n/it.po new file mode 100644 index 000000000000..e4f839ccf347 --- /dev/null +++ b/fiscal_epos_print/i18n/it.po @@ -0,0 +1,1019 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fiscal_epos_print +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-10-05 17:06+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 5.6.2\n" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/pos_order_mgmt.js:0 +#, python-format +msgid ": order already has a fiscal number, " +msgstr ": l'ordine ha già un numero fiscale, " + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "Fiscal Printer Serial" +msgstr "Seriale stampante fiscale" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "Printer address" +msgstr "Indirizzo stampante" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_needaction +msgid "Action Needed" +msgstr "Azione richiesta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "An error happened while sending data to the printer. Error code: " +msgstr "" +"Si è verificato un errore nell'invio dei dati alla stampante. Codice errore: " + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "Apply" +msgstr "Applica" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_attachment_count +msgid "Attachment Count" +msgstr "Conteggio allegati" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_hr_employee_base +msgid "Basic Employee" +msgstr "Dipendente base" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js:0 +#: code:addons/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js:0 +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "Cancel" +msgstr "Annulla" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__0 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__0 +msgid "Cash" +msgstr "Contanti" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "CashDrawer Opened" +msgstr "Cassetto registratore aperto" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__1 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__1 +msgid "Cheque" +msgstr "Assegno" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Close" +msgstr "Chiudi" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Closing Seq." +msgstr "Seq. di chiusura" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Closure Report Z (Fiscal)" +msgstr "Report Z di chiusura (fiscale)" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_report +msgid "Closure reference" +msgstr "Riferimento chiusura" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_res_config_settings +msgid "Config Settings" +msgstr "Impostazioni configurazione" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js:0 +#, python-format +msgid "Confirm ?" +msgstr "Confermare ?" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Confirm Printer Daily Financial Report (Report X)?" +msgstr "Confermare stampa finanziaria giornaliera (rendiconto X)?" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Confirm Printer Fiscal Closure (Report Z)?" +msgstr "Confermare stampa chiusura fiscale (rendiconto Z)?" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/pos_order_mgmt.js:0 +#, python-format +msgid "Connecting to the fiscal printer" +msgstr "Connessione alla stampante fiscale" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Connection to the printer failed" +msgstr "Connessione alla stampante non riuscita" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__2 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__2 +msgid "Credit or Credit Card" +msgstr "Accredito o carta di credito" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_printer_debug_info +msgid "Debug info" +msgstr "Informazioni debug" + +#. module: fiscal_epos_print +#. odoo-python +#: code:addons/fiscal_epos_print/models/account.py:0 +#, python-format +msgid "Department ID number range [1 - 99]" +msgstr "Intervallo numero ID reparto [1-99]" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_tax__fpdeptax +msgid "Department on fiscal printer 1~99" +msgstr "Reparto sulla stampante fiscale 1~99" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Discount" +msgstr "Sconto" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__6 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__6 +msgid "Discount on payment" +msgstr "Sconto al pagamento" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_doc_num +msgid "Document Number" +msgstr "Numero documento" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_index +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_index +msgid "Electronic Payment / Ticket Index" +msgstr "Indice pagamento elettronico / scontrino" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_hr_employee +msgid "Employee" +msgstr "Dipendente" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Epson ePOS" +msgstr "ePOS Epson" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml:0 +#, python-format +msgid "Epson ePOS Operation" +msgstr "Operazione ePOS Epson" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js:0 +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "Error" +msgstr "Errore" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Error Message: " +msgstr "Messaggio di errore " + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Error on last ESC/POS command with Fiscal/Non fiscal closed" +msgstr "Errore ultimo comando ESC/POS con Fiscale/Non fiscale chiuso" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Error on last ESC/POS command with Non fiscal open" +msgstr "Errore ultimo comando ESC/POS con Non fiscale aperto" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Files waiting to be sent: " +msgstr "File in attesa di invio: " + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Financial Report X" +msgstr "Rendiconto finanziario X" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Finished" +msgstr "Completata" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_operator_number +msgid "Fiscal Operator" +msgstr "Operatore fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__fiscal_cashdrawer +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__fiscal_cashdrawer +msgid "Fiscal Printer Open CashDrawer" +msgstr "Aprire cassetto contanti stampante fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee__fiscal_operator_number +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__fiscal_operator_number +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_public__fiscal_operator_number +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_users__fiscal_operator_number +msgid "Fiscal Printer Operator" +msgstr "Operatore stampa fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__fiscal_printer_serial +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_printer_serial +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__fiscal_printer_serial +msgid "Fiscal Printer Serial" +msgstr "Seriale stampante fiscale" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Fiscal closure" +msgstr "Chiusura fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_z_rep_number +msgid "Fiscal closure number" +msgstr "Numero chiusura fiscale" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Fiscal document open" +msgstr "Documento fiscale aperto" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Fiscal open" +msgstr "Fiscale aperto" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "Fiscal printer" +msgstr "Stampante fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_receipt_amount +msgid "Fiscal receipt amount" +msgstr "Importo ricevuta fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_receipt_date +msgid "Fiscal receipt date" +msgstr "Data ricevuta fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__fiscal_receipt_number +msgid "Fiscal receipt number" +msgstr "Numero ricevuta fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_follower_ids +msgid "Followers" +msgstr "Seguito da" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguito da (partner)" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "From other measurement device" +msgstr "Da altro dispositivo di misura" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_full_refund +#, python-format +msgid "Full Refund" +msgstr "Rimborso completo" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__has_message +msgid "Has Message" +msgstr "Ha un messaggio" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "IRA files" +msgstr "File ADE" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "IRA status" +msgstr "Stato ADE" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Se selezionata, nuovi messaggi richiedono attenzione." + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "Se selezionata, alcuni messaggi hanno un errore di consegna." + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Invoice recorded" +msgstr "Fattura registrata" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_is_follower +msgid "Is Follower" +msgstr "Segue" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_account_journal +msgid "Journal" +msgstr "Registro" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "Lottery" +msgstr "Lotteria" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetLotteryCodeButton.js:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/SetLotteryCodeButton.xml:0 +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__lottery_code +#, python-format +msgid "Lottery Code" +msgstr "Codice lotteria" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_main_attachment_id +msgid "Main Attachment" +msgstr "Allegato principale" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "Manca iva su prodotto" +msgstr "Manca l'IVA sul prodotto" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Max 4 numbers" +msgstr "Massimo 4 numeri" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_has_error +msgid "Message Delivery error" +msgstr "Errore di consegna messaggio" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_ids +msgid "Messages" +msgstr "Messaggi" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js:0 +#, python-format +msgid "Must select a refund order before clicking on this button!" +msgstr "" +"È necessario selezionare un ordine di rimborso prima di fare clic su questo " +"pulsante!" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Negative receipt" +msgstr "Ricevuta in negativo" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "Network error" +msgstr "Errore di rete" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__5 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__5 +msgid "No Paid" +msgstr "Non pagato" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/models.js:0 +#, python-format +msgid "No taxes found" +msgstr "Nessuna imposta trovata" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Non fiscal open" +msgstr "Non fiscale aperto" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_needaction_counter +msgid "Number of Actions" +msgstr "Numero di azioni" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__message_has_error_counter +msgid "Number of errors" +msgstr "Numero di errori" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Numero di messaggi che richiedono un'azione" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Numero di messaggi con errore di consegna" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Offline (end of paper or open cover)" +msgstr "Offline (fine carta o coperchio aperto)" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js:0 +#: code:addons/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js:0 +#, python-format +msgid "Ok" +msgstr "Ok" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Old files: " +msgstr "Vecchi file: " + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Open CashDrawer" +msgstr "Aprire cassetto" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Operations" +msgstr "Operazioni" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/pos_order_mgmt.js:0 +#, python-format +msgid "Order already printed" +msgstr "Ordine già stampato" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Paper running low" +msgstr "Carta in esaurimento" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Payment" +msgstr "Pagamento" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Payment in progress" +msgstr "Pagamento in corso" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_type +msgid "Payment type" +msgstr "Tipo pagamento" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Please confirm to execute the Printer Daily Financial Report" +msgstr "" +"Confermare per eseguire la stampa del rendiconto finanziario giornaliero" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Please confirm to execute the Printer Fiscal Closure" +msgstr "Confermare per eseguire le stampa della chiusura fiscale" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Please confirm to reprint the last receipt" +msgstr "Confermare la ristampa dell'ultimo scontrino" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_config +msgid "Point of Sale Configuration" +msgstr "Configurazione punto vendita" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_order +msgid "Point of Sale Orders" +msgstr "Ordini punto vendita" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_payment_method +msgid "Point of Sale Payment Methods" +msgstr "Metodi di pagamento punto vendita" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_payment +msgid "Point of Sale Payments" +msgstr "Pagamenti punto vendita" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_pos_session +msgid "Point of Sale Session" +msgstr "Sessione punto vendita" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Previous" +msgstr "Precedente" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__printer_ip +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__printer_ip +msgid "Printer IP Address" +msgstr "Indirizzo IP stampante" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Printer can not be reached" +msgstr "La stampante non può essere raggiunta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Printing error" +msgstr "Errore di stampa" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "" +"Product prices on receipts must be set to 'Tax-Included Price' in POS " +"configuration" +msgstr "" +"Nella configurazione POS, i prezzi dei prodotti sugli scontrini devono " +"essere impostati \"Prezzo IVA inclusa\"" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "RT Serial" +msgstr "Seriale REA" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "RT data" +msgstr "Dati REA" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "Receipt" +msgstr "Ricevuta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Receipt Date" +msgstr "Data ricevuta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "Receipt Num." +msgstr "Num. ricevuta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Receipt sent to the printer" +msgstr "Ricevuta inviata alla stampante" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_cash_fiscal_serial +msgid "Refund Cash Serial" +msgstr "Matricola REA" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/SetRefundInfoButton.xml:0 +#, python-format +msgid "Refund Data" +msgstr "Dati rimborso" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_pos_form_refund_info +msgid "Refund Info" +msgstr "Informazioni rimborso" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js:0 +#, python-format +msgid "Refund Information Details" +msgstr "Dettagli informazioni rimborso" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "Refund Information Not Present" +msgstr "Informazioni rimborso non presenti" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_order__refund_date +msgid "Refund date reference" +msgstr "Riferimento data rimborso" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Refund: " +msgstr "Rimborso: " + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Rejected files: " +msgstr "File rifiutati: " + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Reports" +msgstr "Resoconti" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Reprint Last Receipt" +msgstr "Ristampa ultima ricevuta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js:0 +#, python-format +msgid "Reprint Last Receipt?" +msgstr "Ristampare ultima ricevuta?" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Reprint last receipt" +msgstr "Ristampa ultima ricevuta" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/pos.xml:0 +#, python-format +msgid "Retry" +msgstr "Riprova" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/SetReprintButton.xml:0 +#, python-format +msgid "Ristampa Ultimo Scontrino" +msgstr "Ristampa ultimo scontrino" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/ChromeWidgets/SetReprintButton.js:0 +#, python-format +msgid "Ristampa ultimo scontrino?" +msgstr "Ristampa ultimo scontrino?" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Rounding" +msgstr "Arrotondamento" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Running low" +msgstr "In esaurimento" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Send fiscal X report to the fiscal printer" +msgstr "Inviare rendiconto finanziario X alla stampante fiscale" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Send fiscal closure command to the fiscal printer" +msgstr "Inviare comando di chiusura fiscale alla stampante fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_index +#: model:ir.model.fields,help:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_index +msgid "Set the index of the given payment type to specify the detail." +msgstr "Impostare l'indice del tipo pagamento per indicare il dettaglio." + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__show_receipt_when_printing +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__show_receipt_when_printing +msgid "Show receipt on screen when printing" +msgstr "Mostrare a schermo lo scontrino in fase di stampa" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "Some fields are empty." +msgstr "Alcuni campi sono vuoti." + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml:0 +#, python-format +msgid "Status of files to be sent to IRA" +msgstr "Stato dei file da inviare all'ADE" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "SubTotal" +msgstr "Totale parziale" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_account_tax +msgid "Tax" +msgstr "Imposta" + +#. module: fiscal_epos_print +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_apos_payment_method_form_fp90 +msgid "Termini pagamento stampante" +msgstr "Termini pagamento stampante" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_pos_config__printer_ip +#: model:ir.model.fields,help:fiscal_epos_print.field_res_config_settings__printer_ip +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_pos_config_printer_form +#: model_terms:ir.ui.view,arch_db:fiscal_epos_print.view_res_config_settings_printer_form +msgid "The hostname or IP address of the fiscal printer" +msgstr "L'hostname o indirizzo IP della stampante fiscale" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_account_journal__fiscalprinter_payment_type +#: model:ir.model.fields,help:fiscal_epos_print.field_pos_payment_method__fiscalprinter_payment_type +msgid "The payment type to send to the Fiscal Printer." +msgstr "Tipo di pagamento da inviare alla stampante fiscale." + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "" +"The refund information aren't present. Please insert them before printing " +"the receipt" +msgstr "" +"Le informazioni del rimborso non sono presenti, inserirle prima di stampare " +"lo scontrino" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__3 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__3 +msgid "Ticket" +msgstr "Biglietto" + +#. module: fiscal_epos_print +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__account_journal__fiscalprinter_payment_type__4 +#: model:ir.model.fields.selection,name:fiscal_epos_print.selection__pos_payment_method__fiscalprinter_payment_type__4 +msgid "Ticket with number" +msgstr "Biglietto con numero" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Title closed" +msgstr "Titolo chiuso" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Title open" +msgstr "Titolo aperto" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "To format" +msgstr "Da formattare" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_pos_config__use_https +#: model:ir.model.fields,field_description:fiscal_epos_print.field_res_config_settings__use_https +msgid "Use https" +msgstr "Usa HTTPS" + +#. module: fiscal_epos_print +#: model:ir.model,name:fiscal_epos_print.model_res_users +msgid "User" +msgstr "Utente" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Waiting for receipt closing in JAVAPOS mode" +msgstr "Attesa chiusura scontrino modalità JAVAPOS" + +#. module: fiscal_epos_print +#: model:ir.model.fields,field_description:fiscal_epos_print.field_hr_employee_base__website_message_ids +msgid "Website Messages" +msgstr "Messaggi sito web" + +#. module: fiscal_epos_print +#: model:ir.model.fields,help:fiscal_epos_print.field_hr_employee_base__website_message_ids +msgid "Website communication history" +msgstr "Cronologia comunicazioni sito web" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#: code:addons/fiscal_epos_print/static/src/js/epson_epos_print.js:0 +#, python-format +msgid "Wrong answer" +msgstr "Risposta errata" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js:0 +#, python-format +msgid "Wrong tax configuration" +msgstr "Configurazione imposta errata" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/lottery.xml:0 +#, python-format +msgid "XXXXXXXX" +msgstr "XXXXXXXX" + +#. module: fiscal_epos_print +#. odoo-javascript +#: code:addons/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml:0 +#, python-format +msgid "YYYY-MM-DD" +msgstr "YYYY-MM-DD" diff --git a/fiscal_epos_print/models/__init__.py b/fiscal_epos_print/models/__init__.py new file mode 100644 index 000000000000..fc90c29a14a3 --- /dev/null +++ b/fiscal_epos_print/models/__init__.py @@ -0,0 +1,11 @@ +from . import pos_payment +from . import pos_payment_method +from . import point_of_sale +from . import account +from . import account_journal +from . import pos_order +from . import pos_session +from . import res_config_settings +from . import res_users +from . import hr_employee_base +from . import hr_employee diff --git a/fiscal_epos_print/models/account.py b/fiscal_epos_print/models/account.py new file mode 100644 index 000000000000..b16ec1570bb7 --- /dev/null +++ b/fiscal_epos_print/models/account.py @@ -0,0 +1,18 @@ +import re + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + +regex = r"^[1-9][0-9]?$" # regular expression to match numbers between [1 - 99] + + +class AccountTax(models.Model): + _inherit = "account.tax" + + fpdeptax = fields.Char("Department on fiscal printer 1~99", size=2, default="1") + + @api.constrains("fpdeptax") + def _validate_fpdeptax(self): + for tax in self: + if not re.search(regex, tax.fpdeptax): + raise ValidationError(_("Department ID number range [1 - 99]")) diff --git a/fiscal_epos_print/models/account_journal.py b/fiscal_epos_print/models/account_journal.py new file mode 100644 index 000000000000..f0ddbd3ffa09 --- /dev/null +++ b/fiscal_epos_print/models/account_journal.py @@ -0,0 +1,25 @@ +from odoo import fields, models + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + fiscalprinter_payment_type = fields.Selection( + [ + ("0", "Cash"), + ("1", "Cheque"), + ("2", "Credit or Credit Card"), + ("3", "Ticket"), + ("4", "Ticket with number"), + ("5", "No Paid"), + ("6", "Discount on payment"), + ], + "Payment type", + help="The payment type to send to the Fiscal Printer.", + default="0", + ) + + fiscalprinter_payment_index = fields.Integer( + string="Electronic Payment / Ticket Index", + help="Set the index of the given payment type to specify the detail.", + ) diff --git a/fiscal_epos_print/models/hr_employee.py b/fiscal_epos_print/models/hr_employee.py new file mode 100644 index 000000000000..efac145a2fd7 --- /dev/null +++ b/fiscal_epos_print/models/hr_employee.py @@ -0,0 +1,15 @@ +from odoo import api, fields, models + + +class HrEmployeeInherit(models.AbstractModel): + _inherit = "hr.employee" + + fiscal_operator_number = fields.Char( + string="Fiscal Printer Operator", size=1, default="1", tracking=True + ) + + @api.onchange("fiscal_operator_number") + def _onchange_fiscal_operator_number(self): + for rec in self: + if rec.user_id: + rec.user_id.fiscal_operator_number = rec.fiscal_operator_number diff --git a/fiscal_epos_print/models/hr_employee_base.py b/fiscal_epos_print/models/hr_employee_base.py new file mode 100644 index 000000000000..522400220d0c --- /dev/null +++ b/fiscal_epos_print/models/hr_employee_base.py @@ -0,0 +1,10 @@ +from odoo import fields, models + + +class HrEmployeeBaseInherit(models.AbstractModel): + _name = "hr.employee.base" + _inherit = ["hr.employee.base", "mail.thread"] + + fiscal_operator_number = fields.Char( + string="Fiscal Printer Operator", size=1, default="1", tracking=True + ) diff --git a/fiscal_epos_print/models/point_of_sale.py b/fiscal_epos_print/models/point_of_sale.py new file mode 100644 index 000000000000..cfbd0e8fe09d --- /dev/null +++ b/fiscal_epos_print/models/point_of_sale.py @@ -0,0 +1,21 @@ +from odoo import fields, models + + +class PosConfig(models.Model): + _inherit = "pos.config" + + printer_ip = fields.Char( + "Printer IP Address", + help="The hostname or IP address of the fiscal printer", + size=45, + ) + use_https = fields.Boolean( + string="Use https", + default=False, + ) + show_receipt_when_printing = fields.Boolean( + string="Show receipt on screen when printing", default=True + ) + fiscal_printer_serial = fields.Char() + + fiscal_cashdrawer = fields.Boolean(string="Fiscal Printer Open CashDrawer") diff --git a/fiscal_epos_print/models/pos_order.py b/fiscal_epos_print/models/pos_order.py new file mode 100644 index 000000000000..f1b7ed94a579 --- /dev/null +++ b/fiscal_epos_print/models/pos_order.py @@ -0,0 +1,70 @@ +import logging + +from odoo import api, fields, models + +_logger = logging.getLogger(__name__) + + +class PosOrder(models.Model): + _inherit = "pos.order" + + refund_date = fields.Date(string="Refund date reference") + refund_report = fields.Integer(string="Closure reference") + refund_doc_num = fields.Integer(string="Document Number") + refund_cash_fiscal_serial = fields.Char(string="Refund Cash Serial") + refund_full_refund = fields.Boolean(string="Full Refund", default=False) + fiscal_receipt_number = fields.Integer( + string="Fiscal receipt number", + ) + fiscal_receipt_amount = fields.Float("Fiscal receipt amount") + fiscal_receipt_date = fields.Date("Fiscal receipt date") + fiscal_z_rep_number = fields.Integer("Fiscal closure number") + fiscal_printer_serial = fields.Char() + fiscal_printer_debug_info = fields.Text("Debug info", readonly=True) + fiscal_operator_number = fields.Text("Fiscal Operator", readonly=True) + + # TODO allow to save code on customer and load customer, if present + lottery_code = fields.Char() + + @api.model + def _order_fields(self, ui_order): + res = super()._order_fields(ui_order) + res["lottery_code"] = ui_order.get("lottery_code", "") + res["refund_date"] = ui_order.get("refund_date", False) + res["refund_report"] = ui_order.get("refund_report", False) + res["refund_doc_num"] = ui_order.get("refund_doc_num", False) + res["refund_cash_fiscal_serial"] = ui_order.get( + "refund_cash_fiscal_serial", False + ) + res["refund_full_refund"] = ui_order.get("refund_full_refund", False) + res["fiscal_receipt_number"] = ui_order.get("fiscal_receipt_number", False) + res["fiscal_receipt_amount"] = ui_order.get("fiscal_receipt_amount", False) + res["fiscal_receipt_date"] = ui_order.get("fiscal_receipt_date", False) + res["fiscal_z_rep_number"] = ui_order.get("fiscal_z_rep_number", False) + res["fiscal_printer_serial"] = ui_order.get("fiscal_printer_serial", False) + res["fiscal_printer_debug_info"] = ui_order.get( + "fiscal_printer_debug_info", False + ) + res["fiscal_operator_number"] = ui_order.get("fiscal_operator_number", False) + return res + + def _export_for_ui(self, order): + result = super()._export_for_ui(order) + result.update( + { + "lottery_code": order.lottery_code, + "refund_date": order.refund_date, + "refund_report": order.refund_report, + "refund_doc_num": order.refund_doc_num, + "refund_cash_fiscal_serial": order.refund_cash_fiscal_serial, + "refund_full_refund": order.refund_full_refund, + "fiscal_receipt_number": order.fiscal_receipt_number, + "fiscal_receipt_amount": order.fiscal_receipt_amount, + "fiscal_receipt_date": order.fiscal_receipt_date, + "fiscal_z_rep_number": order.fiscal_z_rep_number, + "fiscal_printer_serial": order.fiscal_printer_serial, + "fiscal_printer_debug_info": order.fiscal_printer_debug_info, + "fiscal_operator_number": order.fiscal_operator_number, + } + ) + return result diff --git a/fiscal_epos_print/models/pos_payment.py b/fiscal_epos_print/models/pos_payment.py new file mode 100644 index 000000000000..22320ae09b80 --- /dev/null +++ b/fiscal_epos_print/models/pos_payment.py @@ -0,0 +1,15 @@ +from odoo import models + + +class PosPayment(models.Model): + _inherit = "pos.payment" + + def _export_for_ui(self, payment): + res = super()._export_for_ui(payment) + res[ + "fiscalprinter_payment_type" + ] = payment.payment_method_id.fiscalprinter_payment_type + res[ + "fiscalprinter_payment_index" + ] = payment.payment_method_id.fiscalprinter_payment_index + return res diff --git a/fiscal_epos_print/models/pos_payment_method.py b/fiscal_epos_print/models/pos_payment_method.py new file mode 100644 index 000000000000..d1667e724ae0 --- /dev/null +++ b/fiscal_epos_print/models/pos_payment_method.py @@ -0,0 +1,25 @@ +from odoo import fields, models + + +class PosPaymentMethod(models.Model): + _inherit = "pos.payment.method" + + fiscalprinter_payment_type = fields.Selection( + [ + ("0", "Cash"), + ("1", "Cheque"), + ("2", "Credit or Credit Card"), + ("3", "Ticket"), + ("4", "Ticket with number"), + ("5", "No Paid"), + ("6", "Discount on payment"), + ], + "Payment type", + help="The payment type to send to the Fiscal Printer.", + default="0", + ) + + fiscalprinter_payment_index = fields.Integer( + string="Electronic Payment / Ticket Index", + help="Set the index of the given payment type to specify the detail.", + ) diff --git a/fiscal_epos_print/models/pos_session.py b/fiscal_epos_print/models/pos_session.py new file mode 100644 index 000000000000..7d838354b698 --- /dev/null +++ b/fiscal_epos_print/models/pos_session.py @@ -0,0 +1,32 @@ +# Copyright 2022 Dinamiche Aziendali srl +# @author: Giuseppe Borruso +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class PosSession(models.Model): + _inherit = "pos.session" + + def _loader_params_pos_payment_method(self): + result = super()._loader_params_pos_payment_method() + result["search_params"]["fields"].append("fiscalprinter_payment_type") + result["search_params"]["fields"].append("fiscalprinter_payment_index") + return result + + def _loader_params_account_tax(self): + result = super()._loader_params_account_tax() + result["search_params"]["fields"].append("fpdeptax") + return result + + def _loader_params_hr_employee(self): + result = super()._loader_params_hr_employee() + result["search_params"]["fields"].append("fiscal_operator_number") + return result + + def _get_pos_ui_hr_employee(self, params): + employees = super()._get_pos_ui_hr_employee(params) + for employee in employees: + emp = self.env["hr.employee"].browse(employee["id"]) + employee["fiscal_operator_number"] = emp.fiscal_operator_number + return employees diff --git a/fiscal_epos_print/models/res_config_settings.py b/fiscal_epos_print/models/res_config_settings.py new file mode 100644 index 000000000000..46945b7fa26e --- /dev/null +++ b/fiscal_epos_print/models/res_config_settings.py @@ -0,0 +1,17 @@ +from odoo import fields, models + + +class ResConfigSetting(models.TransientModel): + _inherit = "res.config.settings" + + printer_ip = fields.Char(related="pos_config_id.printer_ip", readonly=False) + use_https = fields.Boolean(related="pos_config_id.use_https", readonly=False) + show_receipt_when_printing = fields.Boolean( + related="pos_config_id.show_receipt_when_printing", readonly=False + ) + fiscal_printer_serial = fields.Char( + related="pos_config_id.fiscal_printer_serial", readonly=False + ) + fiscal_cashdrawer = fields.Boolean( + related="pos_config_id.fiscal_cashdrawer", readonly=False + ) diff --git a/fiscal_epos_print/models/res_users.py b/fiscal_epos_print/models/res_users.py new file mode 100644 index 000000000000..e813b05d7124 --- /dev/null +++ b/fiscal_epos_print/models/res_users.py @@ -0,0 +1,9 @@ +from odoo import fields, models + + +class ResUsersInherit(models.Model): + _inherit = "res.users" + + fiscal_operator_number = fields.Char( + string="Fiscal Printer Operator", size=1, default="1" + ) diff --git a/fiscal_epos_print/pyproject.toml b/fiscal_epos_print/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/fiscal_epos_print/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/fiscal_epos_print/readme/CONFIGURE.md b/fiscal_epos_print/readme/CONFIGURE.md new file mode 100644 index 000000000000..052139dbbd8d --- /dev/null +++ b/fiscal_epos_print/readme/CONFIGURE.md @@ -0,0 +1,25 @@ +**Italiano** + +- stampare la lista dei reparti della vostra stampante fiscale +- mappare le imposta di vendita di odoo con i gruppi di imposte - + dipartimenti della stampante fiscale, per ogni imposta di vendita in + odoo, usando il campo "Reparto sulla stampante fiscale 1~99" +- in odoo, utilizzare imposte incluse nel prezzo +- connettere la vostra stampante fiscale alla rete locale e recuperare + l'IP +- aprire la configurazione POS e impostare l'indirizzo IP e il seriale + della stampante nella sezione "Stampante Fiscale" +- è tutto, alla validazione del pagamento nella sessione POS, il sistema + stamperà lo scontrino fiscale. + +**English** + +- print list departments of your fiscal printer +- map odoo sale taxes with taxes groups - departments of fiscal printer, + for each sale tax on odoo, using field "Department on fiscal printer + 1~99" +- in odoo, use taxes included in price +- connect your fiscal printer to local network and find IP +- open POS configuration and fill Printer IP Address field +- that's all, at validation of payment on POS session, system prints + fiscal receipt. diff --git a/fiscal_epos_print/readme/CONTRIBUTORS.md b/fiscal_epos_print/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..1575d667cd9e --- /dev/null +++ b/fiscal_epos_print/readme/CONTRIBUTORS.md @@ -0,0 +1,6 @@ +- Leonardo Donelli +- [TAKOBI](https://takobi.online): + - Lorenzo Battistini +- Alessio Gerace +- Roberto Fichera +- Giuseppe Borruso \<\> diff --git a/fiscal_epos_print/readme/DESCRIPTION.md b/fiscal_epos_print/readme/DESCRIPTION.md new file mode 100644 index 000000000000..f8fe98d89c16 --- /dev/null +++ b/fiscal_epos_print/readme/DESCRIPTION.md @@ -0,0 +1,19 @@ +**Italiano** + +Questo modulo permette di stampare gli scontrini del punto vendita, su +stampanti fiscali Epson, tramite protocollo EPos + +Stampanti supportate: + +- FP81II +- FP90III + +**English** + +This module allows to print receipt of point of sale, on fiscal printers +Epson, via EPos protocol. + +Supported printers: + +- FP81II +- FP90III diff --git a/fiscal_epos_print/readme/ROADMAP.md b/fiscal_epos_print/readme/ROADMAP.md new file mode 100644 index 000000000000..fec2b6652ba4 --- /dev/null +++ b/fiscal_epos_print/readme/ROADMAP.md @@ -0,0 +1,4 @@ +- Resi: + - Aggiungere controllo "rendibilità" + - Stampare sullo scontrino un barcode identificativo, in modo da + generare il reso facendone la scansione diff --git a/fiscal_epos_print/static/description/icon.png b/fiscal_epos_print/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/fiscal_epos_print/static/description/icon.png differ diff --git a/fiscal_epos_print/static/description/index.html b/fiscal_epos_print/static/description/index.html new file mode 100644 index 000000000000..38c172ce8fbf --- /dev/null +++ b/fiscal_epos_print/static/description/index.html @@ -0,0 +1,489 @@ + + + + + +ITA - Driver per stampanti fiscali compatibili ePOS-Print XML + + + +
+

ITA - Driver per stampanti fiscali compatibili ePOS-Print XML

+ + +

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

+

Italiano

+

Questo modulo permette di stampare gli scontrini del punto vendita, su +stampanti fiscali Epson, tramite protocollo EPos

+

Stampanti supportate:

+
    +
  • FP81II
  • +
  • FP90III
  • +
+

English

+

This module allows to print receipt of point of sale, on fiscal printers +Epson, via EPos protocol.

+

Supported printers:

+
    +
  • FP81II
  • +
  • FP90III
  • +
+

Table of contents

+ +
+

Configuration

+

Italiano

+
    +
  • stampare la lista dei reparti della vostra stampante fiscale
  • +
  • mappare le imposta di vendita di odoo con i gruppi di imposte - +dipartimenti della stampante fiscale, per ogni imposta di vendita in +odoo, usando il campo “Reparto sulla stampante fiscale 1~99”
  • +
  • in odoo, utilizzare imposte incluse nel prezzo
  • +
  • connettere la vostra stampante fiscale alla rete locale e recuperare +l’IP
  • +
  • aprire la configurazione POS e impostare l’indirizzo IP e il seriale +della stampante nella sezione “Stampante Fiscale”
  • +
  • è tutto, alla validazione del pagamento nella sessione POS, il +sistema stamperà lo scontrino fiscale.
  • +
+

English

+
    +
  • print list departments of your fiscal printer
  • +
  • map odoo sale taxes with taxes groups - departments of fiscal +printer, for each sale tax on odoo, using field “Department on fiscal +printer 1~99”
  • +
  • in odoo, use taxes included in price
  • +
  • connect your fiscal printer to local network and find IP
  • +
  • open POS configuration and fill Printer IP Address field
  • +
  • that’s all, at validation of payment on POS session, system prints +fiscal receipt.
  • +
+
+
+

Known issues / Roadmap

+
    +
  • Resi:
      +
    • Aggiungere controllo “rendibilità”
    • +
    • Stampare sullo scontrino un barcode identificativo, in modo da +generare il reso facendone la scansione
    • +
    +
  • +
+
+
+

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

+
    +
  • Agile Business Group
  • +
  • Leonardo Donelli
  • +
  • TAKOBI
  • +
  • Level Prime Srl
  • +
+
+
+

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.

+

Current maintainer:

+

eLBati

+

This module is part of the OCA/l10n-italy project on GitHub.

+

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

+
+
+
+ + diff --git a/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js b/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js new file mode 100644 index 000000000000..bf7fbebc39c2 --- /dev/null +++ b/fiscal_epos_print/static/lib/fiscalprint/fiscalprint.js @@ -0,0 +1,1634 @@ +// +// ePOS-Print and Fiscal Print API +// +// Version 1.1.1 +// +// Copyright (C) SEIKO EPSON CORPORATION 2018. All rights reserved. +// + +// 06/12/2012 1.0.0 +// First release. + +// 01/09/2014 1.0.1 +// 1. Added send timeout parameter (argument). +// 2. Added onreceive res_add argument so that complete response can also be returned. +// 3. onerror response generates FP_NO_ANSWER_NETWORK fixed text instead of xhr response. +// 4. encodeBase64Binary object added for future use. + + +// 23/03/2018 1.1.0 +// 1. Added empty node exception handling. +// 2. Added "statusText" string field in result variable as "status" field is Integer which doesn't manage text +// present in certain replies. +// 3. Added callMode argument in send method so that either asynchronous or synchronous mode can be selected. +// Use "async" for asynchronous otherwise defaults to synchronous. +// If null, defaults to async. +// Timeout only valid for async mode. + +// 14/06/2018 1.1.1 +// 1. Added responseText and responseXML fields to onerror result object. + + +// 06/07/2018 1.1.2 +// 1. Added radix to parseInt for best practice. + +(function (window) +{ + + // + // Function: ePOSBuilder constructor + // Description: initialize an ePOS-Print XML Builder object + // Parameters: none + // Return: none + // + function ePOSBuilder() { + // properties + this.message = ''; + // constants + this.FONT_A = 'font_a'; + this.FONT_B = 'font_b'; + this.FONT_C = 'font_c'; + this.FONT_SPECIAL_A = 'special_a'; + this.FONT_SPECIAL_B = 'special_b'; + this.ALIGN_LEFT = 'left'; + this.ALIGN_CENTER = 'center'; + this.ALIGN_RIGHT = 'right'; + this.COLOR_NONE = 'none'; + this.COLOR_1 = 'color_1'; + this.COLOR_2 = 'color_2'; + this.COLOR_3 = 'color_3'; + this.COLOR_4 = 'color_4'; + this.BARCODE_UPC_A = 'upc_a'; + this.BARCODE_UPC_E = 'upc_e'; + this.BARCODE_EAN13 = 'ean13'; + this.BARCODE_JAN13 = 'jan13'; + this.BARCODE_EAN8 = 'ean8'; + this.BARCODE_JAN8 = 'jan8'; + this.BARCODE_CODE39 = 'code39'; + this.BARCODE_ITF = 'itf'; + this.BARCODE_CODABAR = 'codabar'; + this.BARCODE_CODE93 = 'code93'; + this.BARCODE_CODE128 = 'code128'; + this.BARCODE_GS1_128 = 'gs1_128'; + this.BARCODE_GS1_DATABAR_OMNIDIRECTIONAL = 'gs1_databar_omnidirectional'; + this.BARCODE_GS1_DATABAR_TRUNCATED = 'gs1_databar_truncated'; + this.BARCODE_GS1_DATABAR_LIMITED = 'gs1_databar_limited'; + this.BARCODE_GS1_DATABAR_EXPANDED = 'gs1_databar_expanded'; + this.HRI_NONE = 'none'; + this.HRI_ABOVE = 'above'; + this.HRI_BELOW = 'below'; + this.HRI_BOTH = 'both'; + this.SYMBOL_PDF417_STANDARD = 'pdf417_standard'; + this.SYMBOL_PDF417_TRUNCATED = 'pdf417_truncated'; + this.SYMBOL_QRCODE_MODEL_1 = 'qrcode_model_1'; + this.SYMBOL_QRCODE_MODEL_2 = 'qrcode_model_2'; + this.SYMBOL_MAXICODE_MODE_2 = 'maxicode_mode_2'; + this.SYMBOL_MAXICODE_MODE_3 = 'maxicode_mode_3'; + this.SYMBOL_MAXICODE_MODE_4 = 'maxicode_mode_4'; + this.SYMBOL_MAXICODE_MODE_5 = 'maxicode_mode_5'; + this.SYMBOL_MAXICODE_MODE_6 = 'maxicode_mode_6'; + this.SYMBOL_GS1_DATABAR_STACKED = 'gs1_databar_stacked'; + this.SYMBOL_GS1_DATABAR_STACKED_OMNIDIRECTIONAL = 'gs1_databar_stacked_omnidirectional'; + this.SYMBOL_GS1_DATABAR_EXPANDED_STACKED = 'gs1_databar_expanded_stacked'; + this.LEVEL_0 = 'level_0'; + this.LEVEL_1 = 'level_1'; + this.LEVEL_2 = 'level_2'; + this.LEVEL_3 = 'level_3'; + this.LEVEL_4 = 'level_4'; + this.LEVEL_5 = 'level_5'; + this.LEVEL_6 = 'level_6'; + this.LEVEL_7 = 'level_7'; + this.LEVEL_8 = 'level_8'; + this.LEVEL_L = 'level_l'; + this.LEVEL_M = 'level_m'; + this.LEVEL_Q = 'level_q'; + this.LEVEL_H = 'level_h'; + this.LEVEL_DEFAULT = 'default'; + this.LINE_THIN = 'thin'; + this.LINE_MEDIUM = 'medium'; + this.LINE_THICK = 'thick'; + this.LINE_THIN_DOUBLE = 'thin_double'; + this.LINE_MEDIUM_DOUBLE = 'medium_double'; + this.LINE_THICK_DOUBLE = 'thick_double'; + this.DIRECTION_LEFT_TO_RIGHT = 'left_to_right'; + this.DIRECTION_BOTTOM_TO_TOP = 'bottom_to_top'; + this.DIRECTION_RIGHT_TO_LEFT = 'right_to_left'; + this.DIRECTION_TOP_TO_BOTTOM = 'top_to_bottom'; + this.CUT_NO_FEED = 'no_feed'; + this.CUT_FEED = 'feed'; + this.CUT_RESERVE = 'reserve'; + this.DRAWER_1 = 'drawer_1'; + this.DRAWER_2 = 'drawer_2'; + this.PULSE_100 = 'pulse_100'; + this.PULSE_200 = 'pulse_200'; + this.PULSE_300 = 'pulse_300'; + this.PULSE_400 = 'pulse_400'; + this.PULSE_500 = 'pulse_500'; + this.PATTERN_NONE = 'none'; + this.PATTERN_A = 'pattern_a'; + this.PATTERN_B = 'pattern_b'; + this.PATTERN_C = 'pattern_c'; + this.PATTERN_D = 'pattern_d'; + this.PATTERN_E = 'pattern_e'; + this.PATTERN_ERROR = 'error'; + this.PATTERN_PAPER_END = 'paper_end'; + } + + // + // Function: addFeedUnit method + // Description: append the XML element to print and feed paper + // Parameters: + // unit unsignedbyte paper feed amount (units) + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addFeedUnit = function (unit) { + // create empty string + var s = ''; + // check parameter + s += getUByteAttr('unit', unit); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addFeedLine method + // Description: append the XML element to print and feed n lines + // Parameters: + // line unsignedbyte paper feed amount (lines) + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addFeedLine = function (line) { + // create empty string + var s = ''; + // check parameter + s += getUByteAttr('line', line); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addText method + // Description: append the XML element to print characters + // Parameters: + // data string characters + // Return: object ePOSBuilder object + // + ePOSBuilder.prototype.addText = function (data) { + // append element + this.message += '' + encodeXmlEntity(data) + ''; + // return builder object + return this; + } + + // + // Function: addTextLang method + // Description: append the XML element to select language + // Parameters: + // lang string language code and country code (en, en-US, ja, ja-JP, etc.) + // Return: object ePOSBuilder object + // + ePOSBuilder.prototype.addTextLang = function (lang) { + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextAlign method + // Description: append the XML element to set alignment + // Parameters: + // align string alignment (ALIGN_* constants) + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextAlign = function (align) { + // create empty string + var s = ''; + // check parameter + s += getEnumAttr('align', align, regexAlign); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextRotate method + // Description: append the XML element to turn upside-down print mode on/off + // Parameters: + // rotate boolean when true, upside-down print mode is turned on + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextRotate = function (rotate) { + // create empty string + var s = ''; + // check parameter + s += getBoolAttr('rotate', rotate); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextLineSpace method + // Description: append the XML element to set line spacing + // Parameters: + // linespc unsignedByte the amount of line spacing + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextLineSpace = function (linespc) { + // create empty string + var s = ''; + // check parameter + s += getUByteAttr('linespc', linespc); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextFont method + // Description: append the XML element to select character font + // Parameters: + // font string font (FONT_* constants) + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextFont = function (font) { + // create empty string + var s = ''; + // check parameter + s += getEnumAttr('font', font, regexFont); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextSmooth method + // Description: append the XML element to turn smoothing mode on/off + // Parameters: + // smooth boolean when true, smoothing mode is turned on + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextSmooth = function (smooth) { + // create empty string + var s = ''; + // check parameter + s += getBoolAttr('smooth', smooth); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextDouble method + // Description: append the XML element to turn double-wide/double-high mode on/off + // Parameters: + // dw boolean when true, double-wide mode is turned on [option] + // dh boolean when true, double-high mode is turned on [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextDouble = function (dw, dh) { + // create empty string + var s = ''; + // check parameter (option) + if (dw !== undefined) { + s += getBoolAttr('dw', dw); + } + // check parameter (option) + if (dh !== undefined) { + s += getBoolAttr('dh', dh); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextSize method + // Description: append the XML element to select character size + // Parameters: + // width unsignedByte character width (1 to 8) [option] + // height unsignedByte character height (1 to 8) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextSize = function (width, height) { + // create empty string + var s = ''; + // check parameter (option) + if (width !== undefined) { + s += getIntAttr('width', width, 1, 8); + } + // check parameter (option) + if (height !== undefined) { + s += getIntAttr('height', height, 1, 8); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextStyle method + // Description: append the XML element to select character style + // Parameters: + // reverse boolean when true, black/white reverse print mode is turned on [option] + // ul boolean when true, underline mode is turned on [option] + // em boolean when true, emphasized mode is turned on [option] + // color string color (COLOR_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextStyle = function (reverse, ul, em, color) { + // create empty string + var s = ''; + // check parameter (option) + if (reverse !== undefined) { + s += getBoolAttr('reverse', reverse); + } + // check parameter (option) + if (ul !== undefined) { + s += getBoolAttr('ul', ul); + } + // check parameter (option) + if (em !== undefined) { + s += getBoolAttr('em', em); + } + // check parameter (option) + if (color !== undefined) { + s += getEnumAttr('color', color, regexColor); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addTextPosition method + // Description: append the XML element to set absolute print position + // Parameters: + // x unsignedShort X start position + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addTextPosition = function (x) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x', x); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addImage method + // Description: append the XML element to print the graphics data (raster format) + // Parameters: + // context object the 2-D context of HTML 5 Canvas + // x unsignedShort X start position + // y unsignedShort Y start position + // width unsignedShort horizontal size + // height unsignedShort vertical size + // color string color (COLOR_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addImage = function (context, x, y, width, height, color) { + // create empty string + var s = ''; + // check parameter + getUShortAttr('x', x); + // check parameter + getUShortAttr('y', y); + // check parameter + s += getUShortAttr('width', width); + // check parameter + s += getUShortAttr('height', height); + // check parameter (option) + if (color !== undefined) { + s += getEnumAttr('color', color, regexColor); + } + // create image data + var image = encodeRasterImage(context.getImageData(x, y, width, height).data, width, height); + // append element + this.message += '' + encodeBase64Binary(image) + ''; + // return builder object + return this; + } + + // + // Function: addLogo method + // Description: append the XML element to print specified NV graphics data + // Parameters: + // key1 unsignedShort key code 1 + // key2 unsignedShort key code 2 + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addLogo = function (key1, key2) { + // create empty string + var s = ''; + // check parameter + s += getUByteAttr('key1', key1); + // check parameter + s += getUByteAttr('key2', key2); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addBarcode method + // Description: append the XML element to print bar code + // Parameters: + // data object bar code data (characters, escape sequences '\xnn', '\\') + // type string bar code type (BARCODE_* constants) + // hri string print position of HRI characters (HRI_* constants) [option] + // font string font for HRI characters (FONT_* constants) [option] + // width unsignedByte bar code module width [option] + // height unsignedByte bar code module height [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addBarcode = function (data, type, hri, font, width, height) { + // create empty string + var s = ''; + // check parameter + s += getEnumAttr('type', type, regexBarcode); + // check parameter (option) + if (hri !== undefined) { + s += getEnumAttr('hri', hri, regexHri); + } + // check parameter (option) + if (font !== undefined) { + s += getEnumAttr('font', font, regexFont); + } + // check parameter (option) + if (width !== undefined) { + s += getUByteAttr('width', width); + } + // check parameter (option) + if (height !== undefined) { + s += getUByteAttr('height', height); + } + // append element + this.message += '' + escapeText(encodeXmlEntity(data)) + ''; + // return builder object + return this; + } + + // + // Function: addSymbol method + // Description: append the XML element to print two dimension code + // Parameters: + // data object symbol data (characters, escape sequences '\xnn', '\\') + // type string symbol type (SYMBOL_* constants) + // level string error correction level (LEVEL_* constants) [option] + // width unsignedByte module width (PDF417, QR Code, GS1 DataBar) [option] + // height unsignedByte module height (PDF417) [option] + // size unsignedShort the number of columns (PDF417), maximum width (GS1 DataBar) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addSymbol = function (data, type, level, width, height, size) { + // create empty string + var s = ''; + // check parameter + s += getEnumAttr('type', type, regexSymbol); + // check parameter (option) + if (level !== undefined) { + s += getEnumAttr('level', level, regexLevel); + } + // check parameter (option) + if (width !== undefined) { + s += getUByteAttr('width', width); + } + // check parameter (option) + if (height !== undefined) { + s += getUByteAttr('height', height); + } + // check parameter (option) + if (size !== undefined) { + s += getUShortAttr('size', size); + } + // append element + this.message += '' + escapeText(encodeXmlEntity(data)) + ''; + // return builder object + return this; + } + + // + // Function: addCommand method + // Description: append the XML element to send commands + // Parameters: + // data string commands + // Return: object ePOSBuilder object + // + ePOSBuilder.prototype.addCommand = function (data) { + // append element + this.message += '' + encodeHexBinary(data) + ''; + // return builder object + return this; + } + + // + // Function: addHLine method + // Description: append the XML element to draw horizontal line + // Parameters: + // x1 unsignedShort X start position + // x2 unsignedShort X end position + // style string the style of line (LINE_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addHLine = function (x1, x2, style) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x1', x1); + // check parameter + s += getUShortAttr('x2', x2); + // check parameter (option) + if (style !== undefined) { + s += getEnumAttr('style', style, regexLine); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addVLineBegin method + // Description: append the XML element to draw vertical line + // Parameters: + // x unsignedShort X start position + // style string the style of line (LINE_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addVLineBegin = function (x, style) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x', x); + // check parameter (option) + if (style !== undefined) { + s += getEnumAttr('style', style, regexLine); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addVLineEnd method + // Description: append the XML element to draw vertical line + // Parameters: + // x unsignedShort X end position + // style string the style of line (LINE_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addVLineEnd = function (x, style) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x', x); + // check parameter (option) + if (style !== undefined) { + s += getEnumAttr('style', style, regexLine); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPageBegin method + // Description: append the XML element to select page mode + // Parameters: none + // Return: object ePOSBuilder object + // + ePOSBuilder.prototype.addPageBegin = function () { + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPageEnd method + // Description: append the XML element to print and return to standard mode (in page mode) + // Parameters: none + // Return: object ePOSBuilder object + // + ePOSBuilder.prototype.addPageEnd = function () { + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPageArea method + // Description: append the XML element to set print area in page mode + // Parameters: + // x unsignedShort horizontal logical origin + // y unsignedShort vertical logical origin + // width unsignedShort print area width + // height unsignedShort print area height + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addPageArea = function (x, y, width, height) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x', x); + // check parameter + s += getUShortAttr('y', y); + // check parameter + s += getUShortAttr('width', width); + // check parameter + s += getUShortAttr('height', height); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPageDirection method + // Description: append the XML element to select print direction in page mode + // Parameters: + // dir string direction (DIRECTION_* constants) + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addPageDirection = function (dir) { + // create empty string + var s = ''; + // check parameter + s += getEnumAttr('dir', dir, regexDirection); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPagePosition method + // Description: append the XML element to set absolute print position in page mode + // Parameters: + // x unsignedShort horizontal position + // y unsignedShort vertical position + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addPagePosition = function (x, y) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x', x); + // check parameter + s += getUShortAttr('y', y); + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPageLine method + // Description: append the XML element to draw line in page mode + // Parameters: + // x1 unsignedShort X start position + // y1 unsignedShort Y start position + // x2 unsignedShort X end position + // y2 unsignedShort Y end position + // style string the style of line (LINE_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addPageLine = function (x1, y1, x2, y2, style) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x1', x1); + // check parameter + s += getUShortAttr('y1', y1); + // check parameter + s += getUShortAttr('x2', x2); + // check parameter + s += getUShortAttr('y2', y2); + // check parameter (option) + if (style !== undefined) { + s += getEnumAttr('style', style, regexLine); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPageRectangle method + // Description: append the XML element to draw rectangle in page mode + // Parameters: + // x1 unsignedShort X start position + // y1 unsignedShort Y start position + // x2 unsignedShort X end position + // y2 unsignedShort Y end position + // style string the style of line (LINE_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addPageRectangle = function (x1, y1, x2, y2, style) { + // create empty string + var s = ''; + // check parameter + s += getUShortAttr('x1', x1); + // check parameter + s += getUShortAttr('y1', y1); + // check parameter + s += getUShortAttr('x2', x2); + // check parameter + s += getUShortAttr('y2', y2); + // check parameter (option) + if (style !== undefined) { + s += getEnumAttr('style', style, regexLine); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addCut method + // Description: append the XML element to cut paper + // Parameters: + // type string cut mode (CUT_* constants) [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addCut = function (type) { + // create empty string + var s = ''; + // check parameter (option) + if (type !== undefined) { + s += getEnumAttr('type', type, regexCut); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addPulse method + // Description: append the XML element to generate pulse + // Parameters: + // drawer string drawer kick-out connector pin (DRAWER_* constants) [option] + // time string the pulse on/off time [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addPulse = function (drawer, time) { + // create empty string + var s = ''; + // check parameter (option) + if (drawer !== undefined) { + s += getEnumAttr('drawer', drawer, regexDrawer); + } + // check parameter (option) + if (time !== undefined) { + s += getEnumAttr('time', time, regexPulse); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Function: addSound method + // Description: append the XML element to sound buzzer + // Parameters: + // pattern string a pattern (PATTERN_* constants) [option] + // repeat unsignedByte the number of times [option] + // Return: object ePOSBuilder object + // Throws: object invalid parameter + // + ePOSBuilder.prototype.addSound = function (pattern, repeat) { + // create empty string + var s = ''; + // check parameter (option) + if (pattern !== undefined) { + s += getEnumAttr('pattern', pattern, regexPattern); + } + // check parameter (option) + if (repeat !== undefined) { + s += getUByteAttr('repeat', repeat); + } + // append element + this.message += ''; + // return builder object + return this; + } + + // + // Method: toString + // Description: get the ePOS-Print XML message + // Parameters: none + // Return: string XML message + // + ePOSBuilder.prototype.toString = function () { + // append root element + var epos = '' + + this.message + ''; + // return message + return epos; + } + + // + // Function: encodeHexBinary method + // Description: encode binary data to hex binary data + // Parameters: + // s string binary data + // Return: string hex binary data + // + function encodeHexBinary(s) { + var r = ''; + for (i = 0; i < s.length; i++) { + r += ('0' + s.charCodeAt(i).toString(16)).slice(-2); + } + return r; + } + + // + // Function: encodeBase64Binary method + // Description: encode binary data to base64 binary data + // Parameters: + // s string binary data + // Return: string base64 binary data + // + function encodeBase64Binary(s) { + var r = ''; + var l = s.length; + var t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + s += '\x00\x00'; + for (var i = 0; i < l; i += 3) { + var n = (s.charCodeAt(i) << 16) | (s.charCodeAt(i + 1) << 8) | s.charCodeAt(i + 2); + r += t.charAt((n >> 18) & 63) + t.charAt((n >> 12) & 63) + t.charAt((n >> 6) & 63) + t.charAt(n & 63); + } + var p = (3 - l % 3) % 3; + return r.slice(0, r.length - p) + '=='.slice(0, p); + } + + // + // Function: encodeRasterImage method + // Description: encode image data to raster bit image data + // Parameters: + // data byte[] RGBA image data + // w int image width + // h int image height + // Return: string raster bit image data + // + function encodeRasterImage(data, w, h) { + var d8 = [ + [0, 32, 8, 40, 2, 34, 10, 42], + [48, 16, 56, 24, 50, 18, 58, 26], + [12, 44, 4, 36, 14, 46, 6, 38], + [60, 28, 52, 20, 62, 30, 54, 22], + [3, 35, 11, 43, 1, 33, 9, 41], + [51, 19, 59, 27, 49, 17, 57, 25], + [15, 47, 7, 39, 13, 45, 5, 37], + [63, 31, 55, 23, 61, 29, 53, 21] + ]; + var s = '', n = 0, p = 0; + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + var r = data[p++], g = data[p++], b = data[p++], a = data[p++]; + var v = 255 - a + ((r * 29891 + g * 58661 + b * 11448) * a + 12750000) / 25500000; + var d = (d8[y & 7][x & 7] << 2) + 2; + if (v < d) { + n |= 0x80 >> (x & 7); + } + if ((x & 7) == 7 || x == w - 1) { + s += String.fromCharCode(n == 16 ? 32 : n); + n = 0; + } + } + } + return s; + } + + // + // Function: encodeXmlEntity method + // Description: encode markup character to XML entity + // Parameters: + // s string text data + // Return: string text data with XML entity + // + function encodeXmlEntity(s) { + var markup = /[<>&'"\t\n\r]/g; + if (markup.test(s)) { + s = s.replace(markup, function (c) { + var r = ''; + switch (c) { + case '<': + r = '<'; + break; + case '>': + r = '>'; + break; + case '&': + r = '&'; + break; + case "'": + r = '''; + break; + case '"': + r = '"'; + break; + case '\t': + r = ' '; + break; + case '\n': + r = ' '; + break; + case '\r': + r = ' '; + break; + default: + break; + } + return r; + }); + } + return s; + } + + // + // Function: escapeText method + // Description: escape sequence for bar code and symbol + // Parameters: + // s string text data + // Return: string text data with escape sequence + // + function escapeText(s) { + var escape = /[\\\x00-\x1f\x7f-\xff]/g; + if (escape.test(s)) { + s = s.replace(escape, function (c) { + return (c == '\\') ? '\\\\' : '\\x' + ('0' + c.charCodeAt(0).toString(16)).slice(-2); + }); + } + return s; + } + + // + // Function: regular expressions + // Description: enumeration check pattern + // + var regexFont = /^(font_[abc]|special_[ab])$/; + var regexAlign = /^(left|center|right)$/; + var regexColor = /^(none|color_[1-4])$/; + var regexBarcode = /^(upc_[ae]|[ej]an13|[ej]an8|code(39|93|128)|itf|codabar|gs1_128|gs1_databar_(omnidirectional|truncated|limited|expanded))$/; + var regexHri = /^(none|above|below|both)$/; + var regexSymbol = /^(pdf417_(standard|truncated)|qrcode_model_[12]|maxicode_mode_[2-6]|gs1_databar_(stacked(_omnidirectional)?|expanded_stacked))$/; + var regexLevel = /^(level_[0-8lmqh]|default)$/; + var regexLine = /^(thin|medium|thick)(_double)?$/; + var regexDirection = /^(left_to_right|bottom_to_top|right_to_left|top_to_bottom)$/; + var regexCut = /^(no_feed|feed|reserve)$/; + var regexDrawer = /^(drawer_1|drawer_2)$/; + var regexPulse = /^pulse_[1-5]00$/; + var regexPattern = /^(none|pattern_[a-e]|error|paper_end)$/; + + // + // Function: getEnumAttr method + // Description: get a XML attribute from a parameter (enumration) + // Parameters: + // name string parameter name + // value string parameter value + // regex regex check pattern + // Return: string XML attribute (' name="value"') + // Throws: object invalid parameter + // + function getEnumAttr(name, value, regex) { + if (!regex.test(value)) { + throw new Error('Parameter "' + name + '" is invalid'); + } + return ' ' + name + '="' + value + '"'; + } + + // + // Function: getBoolAttr method + // Description: get a XML attribute from a parameter (boolean) + // Parameters: + // name string parameter name + // value boolean parameter value + // Return: string XML attribute (' name="value"') + // + function getBoolAttr(name, value) { + return ' ' + name + '="' + !!value + '"'; + } + + // + // Function: getIntAttr method + // Description: get a XML attribute from a parameter (integer) + // Parameters: + // name string parameter name + // value integer parameter value + // min integer minumum value + // max integer maximum value + // Return: string XML attribute (' name="value"') + // Throws: object invalid parameter + // + function getIntAttr(name, value, min, max) { + if (isNaN(value) || value < min || value > max) { + throw new Error('Parameter "' + name + '" is invalid'); + } + return ' ' + name + '="' + value + '"'; + } + + // + // Function: getUByteAttr method + // Description: get a XML attribute from a parameter (unsigned byte) + // Parameters: + // name string parameter name + // value integer parameter value + // Return: string XML attribute (' name="value"') + // Throws: object invalid parameter + // + function getUByteAttr(name, value) { + return getIntAttr(name, value, 0, 255); + } + + // + // Function: getUShortAttr method + // Description: get a XML attribute from a parameter (unsigned short) + // Parameters: + // name string parameter name + // value integer parameter value + // Return: string XML attribute (' name="value"') + // Throws: object invalid parameter + // + function getUShortAttr(name, value) { + return getIntAttr(name, value, 0, 65535); + } + + // + // Function: ePOSPrint constructor + // Description: initialize an ePOS-Print object + // Parameters: none + // Return: none + // + function ePOSPrint() { + // events + this.onreceive = null; + this.onerror = null; + // constants + this.ASB_NO_RESPONSE = 0x00000001; + this.ASB_PRINT_SUCCESS = 0x00000002; + this.ASB_DRAWER_KICK = 0x00000004; + this.ASB_OFF_LINE = 0x00000008; + this.ASB_COVER_OPEN = 0x00000020; + this.ASB_PAPER_FEED = 0x00000040; + this.ASB_WAIT_ON_LINE = 0x00000100; + this.ASB_PANEL_SWITCH = 0x00000200; + this.ASB_MECHANICAL_ERR = 0x00000400; + this.ASB_AUTOCUTTER_ERR = 0x00000800; + this.ASB_UNRECOVER_ERR = 0x00002000; + this.ASB_AUTORECOVER_ERR = 0x00004000; + this.ASB_RECEIPT_NEAR_END = 0x00020000; + this.ASB_RECEIPT_END = 0x00080000; + this.ASB_BUZZER = 0x01000000; + this.ASB_SPOOLER_IS_STOPPED = 0x80000000; + } + + // + // Function: ePOSprint send method + // Description: send the ePOS-Print XML message + // Parameters: + // address string the address of ePOS-Print service + // request string request message + // Return: none + // Throws: object the browser does not equip XMLHttpRequest + // + ePOSPrint.prototype.send = function (address, request) { + // create SOAP envelope + var soap = '' + + '' + + request + ''; + // create XMLHttpRequest object + var xhr = createXMLHttpRequest(); + xhr.open('POST', address, true); + // set headers + xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8'); + xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); + xhr.setRequestHeader('SOAPAction', '""'); + // receive event + var epos = this; + xhr.onreadystatechange = function () { + // receive response message + if (xhr.readyState == 4) { + if (xhr.status == 200) { + fireReceiveEvent(epos, xhr); + } + else { + fireErrorEvent(epos, xhr); + } + } + } + // send request message + xhr.send(soap); + } + + + /* + Function: createXMLHttpRequest method + Description: create an XMLHttpRequest object + Parameters: none + Return: object XMLHttpRequest object + Throws: object the browser does not equip XMLHttpRequest + */ + + function createXMLHttpRequest() + { + var xhr = null; + if (window.XMLHttpRequest) + { + xhr = new XMLHttpRequest(); + } + else if (window.ActiveXObject) + { + xhr = new ActiveXObject('Msxml2.XMLHTTP'); + } + else + { + throw new Error('XMLHttpRequest is not supported'); + } + return xhr; + } + + + // + // Function: fireReceiveEvent method + // Description: generate the onreceive event + // Parameters: + // epos object ePOSPrint object + // xhr object XMLHttpRequest object + // Return: none + // + function fireReceiveEvent(epos, xhr) { + if (epos.onreceive) { + var res = xhr.responseXML.getElementsByTagName('response'); + if (res.length > 0) { + // fire onreceive event + epos.onreceive({ + success: /^(1|true)$/.test(res[0].getAttribute('success')), + code: res[0].getAttribute('code'), + status: parseInt(res[0].getAttribute('status')) + }); + } + else { + fireErrorEvent(epos, xhr); + } + } + } + + // + // Function: fireErrorEvent method + // Description: generate the onerror event + // Parameters: + // epos object ePOSPrint object + // xhr object XMLHttpRequest object + // Return: none + // + function fireErrorEvent(epos, xhr) { + // fire onerror event + if (epos.onerror) { + epos.onerror({ + status: xhr.status, + responseText: xhr.responseText + }); + } + } + + +// F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L --- F I S C A L + + + /* + Function: fiscalPrint constructor + Description: initialize a fiscalPrint object + Parameters: none + Return: none + */ + + function fiscalPrint() + { + // events + this.onreceive = null; + this.onerror = null; + + // constants + this.ASB_NO_RESPONSE = 0x00000001; + this.ASB_PRINT_SUCCESS = 0x00000002; + this.ASB_DRAWER_KICK = 0x00000004; + this.ASB_OFF_LINE = 0x00000008; + this.ASB_COVER_OPEN = 0x00000020; + this.ASB_PAPER_FEED = 0x00000040; + this.ASB_WAIT_ON_LINE = 0x00000100; + this.ASB_PANEL_SWITCH = 0x00000200; + this.ASB_MECHANICAL_ERR = 0x00000400; + this.ASB_AUTOCUTTER_ERR = 0x00000800; + this.ASB_UNRECOVER_ERR = 0x00002000; + this.ASB_AUTORECOVER_ERR = 0x00004000; + this.ASB_RECEIPT_NEAR_END = 0x00020000; + this.ASB_RECEIPT_END = 0x00080000; + this.ASB_BUZZER = 0x01000000; + this.ASB_SPOOLER_IS_STOPPED = 0x80000000; + } + + + /* + Function: fiscalPrint send method + Description: send the fiscal ePOS-Print XML message + Parameters: + address string The address where fpmate.cgi resides + request string Request message + Return: none + Throws: object The browser does not equip XMLHttpRequest + */ + + fiscalPrint.prototype.send = function (address, request, timeout, callMode) + { + timeout = timeout || 0; + callMode = callMode || "async"; + + // create SOAP envelope + var soap = '\n' + + '\n' + + '\n' + + request + + '\n' + + '\n'; + // create XMLHttpRequest object + var xhr = createXMLHttpRequest(); + if (callMode == "async") + { + xhr.open('POST', address, true); + } + else + { + xhr.open('POST', address, false); // PHIL false = sincrono + } + // set headers + xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8'); + xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT'); + xhr.setRequestHeader('SOAPAction', '""'); + // receive event + var epos = this; + + // PHIL timeout non va con le richieste sincrone + if (callMode == "async") + { + xhr.timeout = timeout; + xhr.ontimeout = function () { + console.log("Timed out!!!"); + fireFiscalErrorEvent(epos, xhr); + } + } + + xhr.onreadystatechange = function () + { + // receive response message + // alert("xhr.readyState = " + xhr.readyState + "\n" + "xhr.status = " + xhr.status); + if (xhr.readyState == 4) + { + if (xhr.status == 200) + { + fireFiscalReceiveEvent(epos, xhr); + } + else + { + fireFiscalErrorEvent(epos, xhr); + } + } + } + + // send request message + xhr.send(soap); + } + + /* + Function: fireFiscalReceiveEvent method + Description: generate the onreceive event + Parameters: + epos object ePOSPrint object + xhr object XMLHttpRequest object + Return: none + */ + + function fireFiscalReceiveEvent(epos, xhr) + { + if (epos.onreceive) + { + // alert ("xhr.responseXML.xml = " + xhr.responseXML.xml); + var res = xhr.responseXML.getElementsByTagName('response'); + if (res.length > 0) + { + // fire onreceive event + var result = + { + success: /^(1|true)$/.test(res[0].getAttribute('success')), + code: res[0].getAttribute('code'), + status: parseInt(res[0].getAttribute('status'), 10), + statusText: res[0].getAttribute('status') + }; + + // look for additional info + var res_add = res[0].getElementsByTagName('addInfo'); + if (res_add.length > 0) + { + var list = res_add[0].getElementsByTagName('elementList'); + var list_len = list.length; + var tag_names_list = list[0].childNodes[0].nodeValue; + var tag_names_array = tag_names_list.split(','); + var add_info = {}; + + for (var tnai = 0; tnai < tag_names_array.length; tnai++) + { + var node = res_add[0].getElementsByTagName(tag_names_array[tnai])[0]; + var node_child = node.childNodes[0]; + var node_val = ""; + // 21/02/2018 Philip Barnett. Alcuni comandi tornano con responseData vuoto. Senza la verifica, possono vericarsi i null Exception. + // Questa riga non ha risolto il problema - if(node_child.nodeValue != null && node_child.nodeValue != "") + try + { + node_val = node_child.nodeValue; + } + catch(err) // Blank lines generate exceptions + { + // node_val = "Elemento " + node.childNodes[0] + " vuoto"; + } + add_info[tag_names_array[tnai]] = node_val; + } + } + else { + var tag_names_array = ""; + var add_info = ""; + } + + epos.onreceive(result, tag_names_array, add_info, res_add) + } + else // res.length <= 0 + { + // alert ("res.length = " + res.length); + } // end if (res.length > 0) + } // end if (epos.onreceive) + } // end function fireFiscalReceiveEvent(epos, xhr) + + + /* + Function: fireFiscalErrorEvent method + Description: generate the onerror event + Parameters: + epos object ePOSPrint object + xhr object XMLHttpRequest object + Return: none + */ + + function fireFiscalErrorEvent(epos, xhr) + { + // fire onerror event + // alert("Error event called"); + if (epos.onerror) + { + var result = + { + success: 'false', + code: "FP_NO_ANSWER_NETWORK", + status: 0, + responseXML: xhr.responseXML, + responseText: xhr.responseText + }; + + epos.onerror(result) + } + } + + + // + // Function: CanvasPrint constructor + // Description: initialize a Canvas-Print object + // Parameters: none + // Return: none + // + + function CanvasPrint() { + } + // inherit from ePOSPrint object + CanvasPrint.prototype = new ePOSPrint(); + CanvasPrint.prototype.constructor = CanvasPrint; + + // + // Function: print method + // Description: print the HTML 5 Canvas + // Parameters: + // address string the address of ePOS-Print service + // canvas object HTML 5 Canvas object + // cut boolean when true, cut paper [option] + // Return: none + // Throws: object the browser does not equip Canvas + // + CanvasPrint.prototype.print = function (address, canvas, cut) { + // check parameter + if (!canvas.getContext) { + throw new Error('Canvas is not supported'); + } + // get HTML 5 Canvas + var context = canvas.getContext('2d'); + var width = canvas.getAttribute('width'); + var height = canvas.getAttribute('height'); + // create ePOS-Print XML message + var builder = new ePOSBuilder(); + builder.addImage(context, 0, 0, width, height); + if (cut) { + builder.addCut(builder.CUT_FEED); + } + // send request message + this.send(address, builder.toString()); + }; + + + /* + Function: epson object + Description: append constructors to window object + */ + + // Core module 'pos_epson_printer' appends constructors to the same window object so + // this implementation avoid to override the epson object. + if (!window.epson) { + window.epson = {} + } + window.epson.ePOSBuilder = window.epson.ePOSBuilder || ePOSBuilder + window.epson.ePOSPrint = window.epson.ePOSPrint || ePOSPrint + window.epson.CanvasPrint = window.epson.CanvasPrint || CanvasPrint + window.epson.fiscalPrint = fiscalPrint + window.epson.encodeBase64Binary = encodeBase64Binary + + +})(window); + + +/* +Function: decodeFpStatus +Description: Decodes the five printer status bytes +Parameters: add_info.fpstatus +Return: printer, ej, receipt, cash_drawer and mode +*/ + + +/* +function decodeFpStatus(add_info.fpStatus) +{ + + var printer = ""; + var ej = ""; + var cash_drawer = ""; + var receipt = ""; + var mode = ""; + + switch(add_info.fpStatus.substring(0,1)) { + case "0": + printer = "OK"; + break; + case "2": + printer = "Carta in esaurimento"; + break; + case "3": + printer = "Offline (fine carta o coperchio aperto)"; + break; + default: + printer = "Risposta errata"; + } + + switch(add_info.fpStatus.substring(1,2)) { + case "0": + ej = "OK"; + break; + case "1": + ej = "Prossimo ad Esaurimento"; + break; + case "2": + ej = "Da formattare"; + break; + case "3": + ej = "Precedente"; + break; + case "4": + ej = "Di altro misuratore"; + break; + case "5": + ej = "Esaurito"; + break; + default: + ej = "Risposta errata"; + } + + switch(add_info.fpStatus.substring(2,3)) { + case "0": + cash_drawer = "Aperto"; + break; + case "1": + cash_drawer = "Chiuso"; + break; + default: + cash_drawer = "Risposta errata"; + } + + switch(add_info.fpStatus.substring(3,4)) { + case "0": + receipt = "Fiscale aperto"; + break; + case "1": + receipt = "Fiscale/Non fiscale chiuso"; + break; + case "2": + receipt = "Non fiscale aperto"; + break; + case "3": + receipt = "Pagamento in corso"; + break; + case "4": + receipt = "Errore ultimo comando ESC/POS con Fiscale/Non fiscale chiuso"; + break; + case "5": + receipt = "Scontrino in negativo"; + break; + case "6": + receipt = "Errore ultimo comando ESC/POS con Non fiscale aperto"; + break; + case "7": + receipt = "Attesa chiusura scontrino modalità JAVAPOS"; + break; + case "8": + receipt = "Documento fiscale aperto"; + break; + case "A": + receipt = "Titolo aperto"; + break; + case "2": + receipt = "Titolo chiuso"; + break; + default: + receipt = "Risposta errata"; + } + + switch(add_info.fpStatus.substring(4,5)) { + case "0": + mode = "Stato registrazione"; + break; + case "1": + mode = "Stato X"; + break; + case "2": + mode = "Stato Z"; + break; + case "3": + mode = "Stato Set"; + break; + default: + mode = "Risposta errata"; + } +} +*/ diff --git a/fiscal_epos_print/static/lib/pikaday/pikaday.min.css b/fiscal_epos_print/static/lib/pikaday/pikaday.min.css new file mode 100644 index 000000000000..92f41e33c90b --- /dev/null +++ b/fiscal_epos_print/static/lib/pikaday/pikaday.min.css @@ -0,0 +1,5 @@ +@charset "UTF-8";/*! + * Pikaday + * Copyright © 2014 David Bushell | BSD & MIT license | https://dbushell.com/ + */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.has-event .pika-button,.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.has-event .pika-button{background:#005da9;box-shadow:inset 0 1px 3px #0076c9}.is-disabled .pika-button,.is-inrange .pika-button{background:#d5e9f7}.is-startrange .pika-button{color:#fff;background:#6cb31d;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.is-outside-current-month .pika-button{color:#999;opacity:.3}.is-selection-disabled{pointer-events:none;cursor:default}.pika-button:hover,.pika-row.pick-whole-week:hover .pika-button{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help} +/*# sourceMappingURL=pikaday.min.css.map */ \ No newline at end of file diff --git a/fiscal_epos_print/static/lib/pikaday/pikaday.min.js b/fiscal_epos_print/static/lib/pikaday/pikaday.min.js new file mode 100644 index 000000000000..078c1b5d6238 --- /dev/null +++ b/fiscal_epos_print/static/lib/pikaday/pikaday.min.js @@ -0,0 +1 @@ +!function(e,t){"use strict";var n;if("object"==typeof exports){try{n=require("moment")}catch(e){}module.exports=t(n)}else"function"==typeof define&&define.amd?define(function(e){try{n=e("moment")}catch(e){}return t(n)}):e.Pikaday=t(e.moment)}(this,function(n){"use strict";var s="function"==typeof n,o=!!window.addEventListener,c=window.document,h=window.setTimeout,r=function(e,t,n,a){o?e.addEventListener(t,n,!!a):e.attachEvent("on"+t,n)},t=function(e,t,n,a){o?e.removeEventListener(t,n,!!a):e.detachEvent("on"+t,n)},l=function(e,t){return-1!==(" "+e.className+" ").indexOf(" "+t+" ")},f=function(e,t){l(e,t)||(e.className=""===e.className?t:e.className+" "+t)},g=function(e,t){var n;e.className=(n=(" "+e.className+" ").replace(" "+t+" "," ")).trim?n.trim():n.replace(/^\s+|\s+$/g,"")},y=function(e){return/Array/.test(Object.prototype.toString.call(e))},F=function(e){return/Date/.test(Object.prototype.toString.call(e))&&!isNaN(e.getTime())},L=function(e,t){return[31,(n=e,n%4==0&&n%100!=0||n%400==0?29:28),31,30,31,30,31,31,30,31,30,31][t];var n},P=function(e){F(e)&&e.setHours(0,0,0,0)},B=function(e,t){return e.getTime()===t.getTime()},d=function(e,t,n){var a,i;for(a in t)(i=void 0!==e[a])&&"object"==typeof t[a]&&null!==t[a]&&void 0===t[a].nodeName?F(t[a])?n&&(e[a]=new Date(t[a].getTime())):y(t[a])?n&&(e[a]=t[a].slice(0)):e[a]=d({},t[a],n):!n&&i||(e[a]=t[a]);return e},i=function(e,t,n){var a;c.createEvent?((a=c.createEvent("HTMLEvents")).initEvent(t,!0,!1),a=d(a,n),e.dispatchEvent(a)):c.createEventObject&&(a=c.createEventObject(),a=d(a,n),e.fireEvent("on"+t,a))},a=function(e){return e.month<0&&(e.year-=Math.ceil(Math.abs(e.month)/12),e.month+=12),11';t.push("is-outside-current-month"),e.enableSelectionDaysInNextAndPreviousMonths||t.push("is-selection-disabled")}return e.isDisabled&&t.push("is-disabled"),e.isToday&&t.push("is-today"),e.isSelected&&(t.push("is-selected"),n="true"),e.hasEvent&&t.push("has-event"),e.isInRange&&t.push("is-inrange"),e.isStartRange&&t.push("is-startrange"),e.isEndRange&&t.push("is-endrange"),'"},p=function(e,t,n,a,i,s){var o,r,l,h,d,u=e._o,c=n===u.minYear,f=n===u.maxYear,g='
',m=!0,p=!0;for(l=[],o=0;o<12;o++)l.push('");for(h='
'+u.i18n.months[a]+'
",y(u.yearRange)?(o=u.yearRange[0],r=u.yearRange[1]+1):(o=n-u.yearRange,r=1+n+u.yearRange),l=[];o=u.minYear&&l.push('");return d='
'+n+u.yearSuffix+'
",u.showMonthAfterYear?g+=d+h:g+=h+d,c&&(0===a||u.minMonth>=a)&&(m=!1),f&&(11===a||u.maxMonth<=a)&&(p=!1),0===t&&(g+='"),t===e._o.numberOfMonths-1&&(g+='"),g+"
"},V=function(e,t,n){return''+function(e){var t,n=[];for(e.showWeekNumber&&n.push(""),t=0;t<7;t++)n.push('");return""+(e.isRTL?n.reverse():n).join("")+""}(e)+(""+t.join("")+"")+"
'+m(e,t,!0)+"
"},e=function(e){var a=this,i=a.config(e);a._onMouseDown=function(e){if(a._v){var t=(e=e||window.event).target||e.srcElement;if(t)if(l(t,"is-disabled")||(!l(t,"pika-button")||l(t,"is-empty")||l(t.parentNode,"is-disabled")?l(t,"pika-prev")?a.prevMonth():l(t,"pika-next")&&a.nextMonth():(a.setDate(new Date(t.getAttribute("data-pika-year"),t.getAttribute("data-pika-month"),t.getAttribute("data-pika-day"))),i.bound&&h(function(){a.hide(),i.blurFieldOnSelect&&i.field&&i.field.blur()},100))),l(t,"pika-select"))a._c=!0;else{if(!e.preventDefault)return e.returnValue=!1;e.preventDefault()}}},a._onChange=function(e){var t=(e=e||window.event).target||e.srcElement;t&&(l(t,"pika-select-month")?a.gotoMonth(t.value):l(t,"pika-select-year")&&a.gotoYear(t.value))},a._onKeyChange=function(e){if(e=e||window.event,a.isVisible())switch(e.keyCode){case 13:case 27:i.field&&i.field.blur();break;case 37:e.preventDefault(),a.adjustDate("subtract",1);break;case 38:a.adjustDate("subtract",7);break;case 39:a.adjustDate("add",1);break;case 40:a.adjustDate("add",7)}},a._onInputChange=function(e){var t;e.firedBy!==a&&(t=i.parse?i.parse(i.field.value,i.format):s?(t=n(i.field.value,i.format,i.formatStrict))&&t.isValid()?t.toDate():null:new Date(Date.parse(i.field.value)),F(t)&&a.setDate(t),a._v||a.show())},a._onInputFocus=function(){a.show()},a._onInputClick=function(){a.show()},a._onInputBlur=function(){var e=c.activeElement;do{if(l(e,"pika-single"))return}while(e=e.parentNode);a._c||(a._b=h(function(){a.hide()},50)),a._c=!1},a._onClick=function(e){var t=(e=e||window.event).target||e.srcElement,n=t;if(t){!o&&l(t,"pika-select")&&(t.onchange||(t.setAttribute("onchange","return;"),r(t,"change",a._onChange)));do{if(l(n,"pika-single")||n===i.trigger)return}while(n=n.parentNode);a._v&&t!==i.trigger&&n!==i.trigger&&a.hide()}},a.el=c.createElement("div"),a.el.className="pika-single"+(i.isRTL?" is-rtl":"")+(i.theme?" "+i.theme:""),r(a.el,"mousedown",a._onMouseDown,!0),r(a.el,"touchend",a._onMouseDown,!0),r(a.el,"change",a._onChange),i.keyboardInput&&r(c,"keydown",a._onKeyChange),i.field&&(i.container?i.container.appendChild(a.el):i.bound?c.body.appendChild(a.el):i.field.parentNode.insertBefore(a.el,i.field.nextSibling),r(i.field,"change",a._onInputChange),i.defaultDate||(s&&i.field.value?i.defaultDate=n(i.field.value,i.format).toDate():i.defaultDate=new Date(Date.parse(i.field.value)),i.setDefaultDate=!0));var t=i.defaultDate;F(t)?i.setDefaultDate?a.setDate(t,!0):a.gotoDate(t):a.gotoDate(new Date),i.bound?(this.hide(),a.el.className+=" is-bound",r(i.trigger,"click",a._onInputClick),r(i.trigger,"focus",a._onInputFocus),r(i.trigger,"blur",a._onInputBlur)):this.show()};return e.prototype={config:function(e){this._o||(this._o=d({},u,!0));var t=d(this._o,e,!0);t.isRTL=!!t.isRTL,t.field=t.field&&t.field.nodeName?t.field:null,t.theme="string"==typeof t.theme&&t.theme?t.theme:null,t.bound=!!(void 0!==t.bound?t.field&&t.bound:t.field),t.trigger=t.trigger&&t.trigger.nodeName?t.trigger:t.field,t.disableWeekends=!!t.disableWeekends,t.disableDayFn="function"==typeof t.disableDayFn?t.disableDayFn:null;var n=parseInt(t.numberOfMonths,10)||1;if(t.numberOfMonths=4=i&&(this._y=i,!isNaN(o)&&this._m>o&&(this._m=o)),t="pika-title-"+Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,2);for(var l=0;l'+p(this,l,this.calendars[l].year,this.calendars[l].month,this.calendars[0].year,t)+this.render(this.calendars[l].year,this.calendars[l].month,t)+"";this.el.innerHTML=r,n.bound&&"hidden"!==n.field.type&&h(function(){n.trigger.focus()},1),"function"==typeof this._o.onDraw&&this._o.onDraw(this),n.bound&&n.field.setAttribute("aria-label",n.ariaLabel)}},adjustPosition:function(){var e,t,n,a,i,s,o,r,l,h,d,u;if(!this._o.container){if(this.el.style.position="absolute",t=e=this._o.trigger,n=this.el.offsetWidth,a=this.el.offsetHeight,i=window.innerWidth||c.documentElement.clientWidth,s=window.innerHeight||c.documentElement.clientHeight,o=window.pageYOffset||c.body.scrollTop||c.documentElement.scrollTop,u=d=!0,"function"==typeof e.getBoundingClientRect)r=(h=e.getBoundingClientRect()).left+window.pageXOffset,l=h.bottom+window.pageYOffset;else for(r=t.offsetLeft,l=t.offsetTop+t.offsetHeight;t=t.offsetParent;)r+=t.offsetLeft,l+=t.offsetTop;(this._o.reposition&&ia.maxDate||a.disableWeekends&&(void 0,0===(w=R.getDay())||6===w)||a.disableDayFn&&a.disableDayFn(R),isEmpty:I,isStartRange:O,isEndRange:j,isInRange:W,showDaysInNextAndPreviousMonths:a.showDaysInNextAndPreviousMonths,enableSelectionDaysInNextAndPreviousMonths:a.enableSelectionDaysInNextAndPreviousMonths};a.pickWholeWeek&&N&&(M=!0),l.push(H(A)),7==++x&&(a.showWeekNumber&&l.unshift((D=k-o,v=t,b=e,_=void 0,_=new Date(b,0,1),''+Math.ceil(((new Date(b,v,D)-_)/864e5+_.getDay()+1)/7)+"")),r.push((p=l,y=a.isRTL,''+(y?p.reverse():p).join("")+"")),x=0,M=!(l=[]))}return V(a,r,n)},isVisible:function(){return this._v},show:function(){this.isVisible()||(this._v=!0,this.draw(),g(this.el,"is-hidden"),this._o.bound&&(r(c,"click",this._onClick),this.adjustPosition()),"function"==typeof this._o.onOpen&&this._o.onOpen.call(this))},hide:function(){var e=this._v;!1!==e&&(this._o.bound&&t(c,"click",this._onClick),this.el.style.position="static",this.el.style.left="auto",this.el.style.top="auto",f(this.el,"is-hidden"),this._v=!1,void 0!==e&&"function"==typeof this._o.onClose&&this._o.onClose.call(this))},destroy:function(){var e=this._o;this.hide(),t(this.el,"mousedown",this._onMouseDown,!0),t(this.el,"touchend",this._onMouseDown,!0),t(this.el,"change",this._onChange),e.keyboardInput&&t(c,"keydown",this._onKeyChange),e.field&&(t(e.field,"change",this._onInputChange),e.bound&&(t(e.trigger,"click",this._onInputClick),t(e.trigger,"focus",this._onInputFocus),t(e.trigger,"blur",this._onInputBlur))),this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},e}); \ No newline at end of file diff --git a/fiscal_epos_print/static/src/css/pos.css b/fiscal_epos_print/static/src/css/pos.css new file mode 100644 index 000000000000..e92003755081 --- /dev/null +++ b/fiscal_epos_print/static/src/css/pos.css @@ -0,0 +1,83 @@ +/* ********* The Epson ePOS FP81II Widget ********* */ + +.pos .epson-fp81ii-widget { + z-index: 100000; + position: absolute; + right: 10px; + top: 10px; + width: 236px; + font-size: 14px; + + background: rgba(0, 0, 0, 0.82) !important; + color: white; + padding-bottom: 10px; + cursor: move; + -webkit-transform: translate3d(0, 0, 0); +} +.pos .pos-rightheader .header-button > img { + vertical-align: middle; +} +.pos .epson-fp81ii-widget .toggle { + position: absolute; + font-size: 16px; + cursor: pointer; + top: 0px; + right: 0px; + padding: 10px; + padding-right: 15px; +} +.pos .epson-fp81ii-widget .content { + overflow: hidden; +} +.pos .epson-fp81ii-widget h1 { + background: black; + padding-top: 10px; + padding-left: 10px; + margin-top: 0; + margin-bottom: 0; +} +.pos .epson-fp81ii-widget .category { + background: black; + padding-left: 10px; + margin: 0px; + font-weight: bold; + font-size: 16px; + padding-top: 3px; + padding-bottom: 3px; +} +.pos .epson-fp81ii-widget .button { + padding: 5px; + padding-left: 15px; + display: block; + cursor: pointer; +} +.pos .epson-fp81ii-widget .button:hover { + background: #546e7a; +} +.pos .epson-fp81ii-widget .category-label { + position: relative; + padding: 4px; + top: -12px; +} +.pos .epson-fp81ii-widget li img { + min-width: 32px; +} +.pos .epson-fp81ii-widget .button:active { + background: rgba(96, 21, 177, 0.45); +} +.pos .epson-fp81ii-widget .status { + padding: 5px; + padding-left: 15px; + display: block; + cursor: default; +} +.pos .epson-fp81ii-widget .status.on { + background-color: #6cd11d; +} +.pos .epson-fp81ii-widget .event { + padding: 5px; + padding-left: 15px; + display: block; + cursor: default; + background-color: #1e1e1e; +} diff --git a/fiscal_epos_print/static/src/css/pos_reprint.css b/fiscal_epos_print/static/src/css/pos_reprint.css new file mode 100644 index 000000000000..e882fa7fd372 --- /dev/null +++ b/fiscal_epos_print/static/src/css/pos_reprint.css @@ -0,0 +1,20 @@ +.receipt-screen .default-view .actions .reprint_buttons .button { + flex: 1; + border: solid 1px rgb(209, 209, 209); + padding: 1rem; + text-align: center; + border-radius: 3px; + cursor: pointer; + background: rgb(230, 230, 230); +} + +.receipt-screen .default-view .actions .reprint_buttons { + display: flex; + margin: 1rem 0px; +} + +.receipt-screen .default-view .actions .reprint_buttons .printing-error { + background: rgb(255, 0, 0); + border: solid 1px #648b0000 !important; + color: white !important; +} diff --git a/fiscal_epos_print/static/src/img/X.svg b/fiscal_epos_print/static/src/img/X.svg new file mode 100644 index 000000000000..a8b9a34b3358 --- /dev/null +++ b/fiscal_epos_print/static/src/img/X.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fiscal_epos_print/static/src/img/Z.svg b/fiscal_epos_print/static/src/img/Z.svg new file mode 100644 index 000000000000..4eb71e9c0886 --- /dev/null +++ b/fiscal_epos_print/static/src/img/Z.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fiscal_epos_print/static/src/img/ade-logo.svg b/fiscal_epos_print/static/src/img/ade-logo.svg new file mode 100644 index 000000000000..fd785b17addc --- /dev/null +++ b/fiscal_epos_print/static/src/img/ade-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fiscal_epos_print/static/src/img/cashdrawer.svg b/fiscal_epos_print/static/src/img/cashdrawer.svg new file mode 100644 index 000000000000..8f5cd95f3257 --- /dev/null +++ b/fiscal_epos_print/static/src/img/cashdrawer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fiscal_epos_print/static/src/img/epos.svg b/fiscal_epos_print/static/src/img/epos.svg new file mode 100644 index 000000000000..1223ef920660 --- /dev/null +++ b/fiscal_epos_print/static/src/img/epos.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fiscal_epos_print/static/src/img/reprint.svg b/fiscal_epos_print/static/src/img/reprint.svg new file mode 100644 index 000000000000..85037e2220fc --- /dev/null +++ b/fiscal_epos_print/static/src/img/reprint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonEPOSButton.js b/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonEPOSButton.js new file mode 100644 index 000000000000..a92158689f68 --- /dev/null +++ b/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonEPOSButton.js @@ -0,0 +1,27 @@ +odoo.define("fiscal_epos_print.EpsonEPOSButton", function (require) { + "use strict"; + + const PosComponent = require("point_of_sale.PosComponent"); + const Registries = require("point_of_sale.Registries"); + + class EpsonEPOSButton extends PosComponent { + /** + * Method that manage EpsonFP81IIComponent visibility through onClick + * Handler + */ + async onClick() { + var epsonFP81IIComponent = $(".status-buttons .epson-fp81ii-widget"); + if (epsonFP81IIComponent.hasClass("oe_hidden")) { + epsonFP81IIComponent.removeClass("oe_hidden"); + } else { + epsonFP81IIComponent.addClass("oe_hidden"); + } + } + } + + EpsonEPOSButton.template = "EpsonEPOSButton"; + + Registries.Component.add(EpsonEPOSButton); + + return EpsonEPOSButton; +}); diff --git a/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js b/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js new file mode 100644 index 000000000000..7128bf48459f --- /dev/null +++ b/fiscal_epos_print/static/src/js/ChromeWidgets/EpsonFP81IIComponent.js @@ -0,0 +1,208 @@ +odoo.define("fiscal_epos_print.EpsonFP81IIComponent", function (require) { + "use strict"; + + var core = require("web.core"); + var epson_epos_print = require("fiscal_epos_print.epson_epos_print"); + var _t = core._t; + var eposDriver = epson_epos_print.eposDriver; + + const {Gui} = require("point_of_sale.Gui"); + const PosComponent = require("point_of_sale.PosComponent"); + const Registries = require("point_of_sale.Registries"); + + class EpsonFP81IIComponent extends PosComponent { + constructor() { + super(...arguments); + var self = this; + + // For dragging the debug widget around + this.dragging = false; + this.dragpos = { + x: 0, + y: 0, + }; + + function eventpos(event) { + if (event.touches && event.touches[0]) { + return { + x: event.touches[0].screenX, + y: event.touches[0].screenY, + }; + } + return { + x: event.screenX, + y: event.screenY, + }; + } + + this.dragend_handler = function () { + self.dragging = false; + }; + this.dragstart_handler = function (event) { + self.dragging = true; + self.dragpos = eventpos(event); + }; + this.dragmove_handler = function (event) { + if (self.dragging) { + var top = this.offsetTop; + var left = this.offsetLeft; + var pos = eventpos(event); + var dx = pos.x - self.dragpos.x; + var dy = pos.y - self.dragpos.y; + + self.dragpos = pos; + + this.style.right = "auto"; + this.style.bottom = "auto"; + this.style.left = left + dx + "px"; + this.style.top = top + dy + "px"; + } + event.preventDefault(); + event.stopPropagation(); + }; + } + + OnMounted() { + // Jquery reference of the component + this.$el = $(this.el); + // Drag listeners + this.el.addEventListener("mouseleave", this.dragend_handler); + this.el.addEventListener("mouseup", this.dragend_handler); + this.el.addEventListener("touchend", this.dragend_handler); + this.el.addEventListener("touchcancel", this.dragend_handler); + this.el.addEventListener("mousedown", this.dragstart_handler); + this.el.addEventListener("touchstart", this.dragstart_handler); + this.el.addEventListener("mousemove", this.dragmove_handler); + this.el.addEventListener("touchmove", this.dragmove_handler); + } + + do_show() { + var epsonFP81IIComponent = $(".status-buttons .epson-fp81ii-widget"); + epsonFP81IIComponent.removeClass("oe_hidden"); + } + + do_hide() { + var epsonFP81IIComponent = $(".status-buttons .epson-fp81ii-widget"); + epsonFP81IIComponent.addClass("oe_hidden"); + } + + getPrinterOptions() { + var protocol = this.env.pos.config.use_https ? "https://" : "http://"; + var printer_url = + protocol + this.env.pos.config.printer_ip + "/cgi-bin/fpmate.cgi"; + return {url: printer_url}; + } + + onToggleComponent() { + this.do_hide(); + } + + async openCashDrawer() { + this.do_hide(); + // TODO find the same Component method that show loading_* + // this.chrome.loading_show(); + // this.chrome.loading_message(_t('Connecting to the fiscal printer')); + var printer_options = this.getPrinterOptions(); + var fp90 = new eposDriver(printer_options, this); + fp90.printOpenCashDrawer(); + const {confirmed} = await Gui.showPopup("ConfirmPopup", { + title: _t("CashDrawer Opened"), + body: _t("Close"), + }); + if (confirmed) { + fp90.resetPrinter(); + } else { + // TODO not exist + // this.chrome.loading_hide(); + } + } + + async reprintLastReceipt() { + this.do_hide(); + // Var self = this; + // this._super(); + + // TODO find the same Component method that show loading_* + // this.chrome.loading_show(); + // this.chrome.loading_message(_t('Connecting to the fiscal printer')); + var printer_options = this.getPrinterOptions(); + var fp90 = new eposDriver(printer_options, this); + // ConfirmPopup + const {confirmed} = await Gui.showPopup("ConfirmPopup", { + title: _t("Reprint Last Receipt?"), + body: _t("Please confirm to reprint the last receipt"), + }); + if (confirmed) { + fp90.printFiscalReprintLast( + this.env.pos.cashier.fiscal_operator_number || "1" + ); + } else { + // TODO not exist + // this.chrome.loading_hide(); + } + } + + showAdeStatus() { + this.do_hide(); + // TODO find the same Component method that show loading_* + // this.chrome.loading_show(); + // this.chrome.loading_message(_t('Connecting to the fiscal printer')); + var printer_options = this.getPrinterOptions(); + var fp90 = new eposDriver(printer_options, this); + fp90.getStatusOfFilesForADE(); + } + + async fiscalClosing() { + this.do_hide(); + // TODO find the same Component method that show loading_* + // this.chrome.loading_show(); + // this.chrome.loading_message(_t('Connecting to the fiscal printer')); + var printer_options = this.getPrinterOptions(); + var fp90 = new eposDriver(printer_options, this); + // ConfirmPopup + const {confirmed} = await this.showPopup("ConfirmPopup", { + title: _t("Confirm Printer Fiscal Closure (Report Z)?"), + body: _t("Please confirm to execute the Printer Fiscal Closure"), + }); + if (confirmed) { + // Fp90.printFiscalReport(); + fp90.printFiscalXZReport( + this.env.pos.cashier.fiscal_operator_number || "1" + ); + } else { + // TODO not exist + // this.chrome.loading_hide(); + } + } + + async fiscalXreport() { + this.do_hide(); + // TODO find the same Component method that show loading_* + // this.chrome.loading_show(); + // this.chrome.loading_message(_t('Connecting to the fiscal printer')); + var printer_options = this.getPrinterOptions(); + var fp90 = new eposDriver(printer_options, this); + // ConfirmPopup + const {confirmed} = await this.showPopup("ConfirmPopup", { + title: _t("Confirm Printer Daily Financial Report (Report X)?"), + body: _t( + "Please confirm to execute the Printer Daily Financial Report" + ), + }); + if (confirmed) { + fp90.printFiscalXReport( + this.env.pos.cashier.fiscal_operator_number || "1" + ); + } else { + // TODO not exist + // this.chrome.loading_hide(); + } + } + } + + EpsonFP81IIComponent.template = "EpsonFP81IIComponent"; + + Registries.Component.add(EpsonFP81IIComponent); + + return EpsonFP81IIComponent; +}); diff --git a/fiscal_epos_print/static/src/js/ChromeWidgets/SetLotteryCodeButton.js b/fiscal_epos_print/static/src/js/ChromeWidgets/SetLotteryCodeButton.js new file mode 100644 index 000000000000..3c4fbfd73b67 --- /dev/null +++ b/fiscal_epos_print/static/src/js/ChromeWidgets/SetLotteryCodeButton.js @@ -0,0 +1,50 @@ +odoo.define("fiscal_epos_print.SetLotteryCodeButton", function (require) { + "use strict"; + + const PosComponent = require("point_of_sale.PosComponent"); + const ProductScreen = require("point_of_sale.ProductScreen"); + const Registries = require("point_of_sale.Registries"); + const core = require("web.core"); + const _t = core._t; + + class SetLotteryCodeButton extends PosComponent { + render() { + var color = this.lottery_get_button_color(); + $(this.el).css("background", color); + } + + async onClickLotteryCode() { + var self = this; + var current_order = this.env.pos.get_order(); + this.showPopup("LotteryCodePopup", { + title: _t("Lottery Code"), + lottery_code: current_order.lottery_code, + update_lottery_info_button: function () { + self.render(); + }, + }); + } + + lottery_get_button_color() { + var order = this.env.pos.get_order(); + var color = "#e2e2e2"; + if (order.lottery_code) { + color = "lightgreen"; + } + return color; + } + } + + SetLotteryCodeButton.template = "SetLotteryCodeButton"; + + ProductScreen.addControlButton({ + component: SetLotteryCodeButton, + condition: function () { + return this.env.pos; + }, + }); + + Registries.Component.add(SetLotteryCodeButton); + + return SetLotteryCodeButton; +}); diff --git a/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js b/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js new file mode 100644 index 000000000000..ffef84e1ba9c --- /dev/null +++ b/fiscal_epos_print/static/src/js/ChromeWidgets/SetRefundInfoButton.js @@ -0,0 +1,133 @@ +odoo.define("fiscal_epos_print.SetRefundInfoButton", function (require) { + "use strict"; + + const PosComponent = require("point_of_sale.PosComponent"); + const ProductScreen = require("point_of_sale.ProductScreen"); + const Registries = require("point_of_sale.Registries"); + const core = require("web.core"); + const _t = core._t; + + class SetRefundInfoButton extends PosComponent { + onMounted() { + this.bind_order_events(); + this.orderline_change(); + } + + is_available() { + const order = this.env.pos.get_order(); + return order; + } + + render() { + var color = this.refund_get_button_color(); + $(this.el).css("background", color); + } + + async onClickRefund() { + var self = this; + var current_order = this.env.pos.get_order(); + if ( + current_order.refund_date === null || + current_order.refund_date === "" + ) { + this.showPopup("ErrorPopup", { + title: _t("Error"), + body: _t( + "Must select a refund order before clicking on this button!" + ), + }); + } + var dd = ("0" + current_order.refund_date.getDate()).slice(-2); + var mm = ("0" + (current_order.refund_date.getMonth() + 1)).slice(-2); + var yyyy = current_order.refund_date.getFullYear(); + this.showPopup("RefundInfoPopup", { + title: _t("Refund Information Details"), + refund_date: yyyy + "-" + mm + "-" + dd, + refund_report: current_order.refund_report, + refund_doc_num: current_order.refund_doc_num, + refund_cash_fiscal_serial: current_order.refund_cash_fiscal_serial, + update_refund_info_button: function () { + self.render(); + }, + }); + } + + bind_order_events() { + var order = this.env.pos.get_order(); + + if (!order) { + return; + } + + if (this.old_order) { + this.old_order.unbind(null, null, this); + } + + this.env.pos.bind("change:selectedOrder", this.orderline_change, this); + + var lines = order.orderlines; + lines.unbind("add", this.orderline_change, this); + lines.bind("add", this.orderline_change, this); + lines.unbind("remove", this.orderline_change, this); + lines.bind("remove", this.orderline_change, this); + lines.unbind("change", this.orderline_change, this); + lines.bind("change", this.orderline_change, this); + + this.old_order = order; + } + + refund_get_button_color() { + var order = this.env.pos.get_order(); + var color = "#e2e2e2"; + if (order) { + var lines = order.orderlines; + var has_refund = + lines.find(function (line) { + return line.quantity < 0.0; + }) !== undefined; + if (has_refund === true) { + if ( + order.refund_date && + order.refund_date !== "" && + order.refund_doc_num && + order.refund_doc_num !== "" && + order.refund_cash_fiscal_serial && + order.refund_cash_fiscal_serial !== "" && + order.refund_report && + order.refund_report !== "" + ) { + color = "lightgreen"; + } else { + color = "red"; + } + } + } + return color; + } + + orderline_change() { + var order = this.env.pos.get_order(); + if (order) { + var lines = order.orderlines; + order.has_refund = + lines.find(function (line) { + return line.quantity < 0.0; + }) !== undefined; + } + this.render(); + } + } + + SetRefundInfoButton.template = "SetRefundInfoButton"; + + ProductScreen.addControlButton({ + component: SetRefundInfoButton, + condition: function () { + return this.env.pos; + }, + }); + + Registries.Component.add(SetRefundInfoButton); + + return SetRefundInfoButton; +}); diff --git a/fiscal_epos_print/static/src/js/ChromeWidgets/SetReprintButton.js b/fiscal_epos_print/static/src/js/ChromeWidgets/SetReprintButton.js new file mode 100644 index 000000000000..87cea8fbd8f4 --- /dev/null +++ b/fiscal_epos_print/static/src/js/ChromeWidgets/SetReprintButton.js @@ -0,0 +1,57 @@ +odoo.define("fiscal_epos_print.SetReprintButton", function (require) { + "use strict"; + + var epson_epos_print = require("fiscal_epos_print.epson_epos_print"); + var eposDriver = epson_epos_print.eposDriver; + const ReceiptScreen = require("point_of_sale.ReceiptScreen"); + const Registries = require("point_of_sale.Registries"); + const {Gui} = require("point_of_sale.Gui"); + const core = require("web.core"); + const _t = core._t; + + const SetReprintButton = (ReceiptScreen) => + class extends ReceiptScreen { + constructor() { + super(...arguments); + if (this.env.pos.get_order()._printed === true) { + var reprintButton = $(".reprint_buttons"); + reprintButton.addClass("oe_hidden"); + } + } + + async rePrintReceipt() { + var currentOrder = this.env.pos.get_order(); + + const {confirmed} = await Gui.showPopup("ConfirmPopup", { + title: _t("Ristampa ultimo scontrino?"), + confirmText: "Conferma", + cancelText: "Annulla", + body: + "Usare la ristampa ultimo scontrino solo in caso di errori di comunicazione con la" + + "stampante e lo scontrino NON è stato stampato. Viene ristampanto uno scontrino FISCALE" + + "con gli stessi articoli del precedente", + }); + if (confirmed) { + var printer_options = this.currentOrder.getPrinterOptions(); + printer_options.order = currentOrder; + var receipt = currentOrder.export_for_printing(); + this.sendToFP90Printer(receipt, printer_options); + } else { + // TODO not exist + } + } + + async sendToFP90Printer(receipt, printer_options) { + var fp90 = new eposDriver(printer_options, this); + const isPrinted = await fp90.printFiscalReceipt(receipt); + if (isPrinted) { + this.currentOrder._printed = true; + } else { + this.currentOrder._printed = false; + } + } + }; + + Registries.Component.extend(ReceiptScreen, SetReprintButton); + return ReceiptScreen; +}); diff --git a/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js b/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js new file mode 100644 index 000000000000..703de9b7b6f6 --- /dev/null +++ b/fiscal_epos_print/static/src/js/Popups/LotteryCodePopup.js @@ -0,0 +1,62 @@ +odoo.define("fiscal_epos_print.LotteryCodePopup", function (require) { + "use strict"; + + const {useRef, useState} = owl; + const AbstractAwaitablePopup = require("point_of_sale.AbstractAwaitablePopup"); + const Registries = require("point_of_sale.Registries"); + const {_lt} = require("@web/core/l10n/translation"); + + class LotteryCodePopup extends AbstractAwaitablePopup { + constructor() { + super(...arguments); + + this.state = useState({inputValue: this.props.startingValue}); + this.inputLotteryCode = useRef("inputLotteryCode"); + } + + clickConfirmLotteryCode() { + this.$el = $(this.el); + var self = this; + function allValid() { + return self.$el + .find("input") + .toArray() + .every(function (element) { + return element.value && element.value !== ""; + }); + } + + if (allValid()) { + this.$el.find("#error-message-dialog").hide(); + + var lottery_code = this.inputLotteryCode.el.value; + this.env.pos.context = { + lottery_code: lottery_code, + }; + this.env.pos.set_lottery_code_data(lottery_code); + if ( + this.props.update_lottery_info_button && + this.props.update_lottery_info_button instanceof Function + ) { + this.props.update_lottery_info_button(); + } + this.env.posbus.trigger("close-popup", {popupId: this.props.id}); + } else { + this.$el.find("#error-message-dialog").show(); + } + } + } + + LotteryCodePopup.template = "LotteryCodePopup"; + + LotteryCodePopup.defaultProps = { + confirmText: _lt("Ok"), + cancelText: _lt("Cancel"), + title: _lt("Confirm ?"), + body: "", + }; + + Registries.Component.add(LotteryCodePopup); + + return LotteryCodePopup; +}); diff --git a/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js b/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js new file mode 100644 index 000000000000..c695302cc247 --- /dev/null +++ b/fiscal_epos_print/static/src/js/Popups/RefundInfoPopup.js @@ -0,0 +1,94 @@ +odoo.define("fiscal_epos_print.RefundInfoPopup", function (require) { + "use strict"; + + const {useRef, useState} = owl; + const AbstractAwaitablePopup = require("point_of_sale.AbstractAwaitablePopup"); + const Registries = require("point_of_sale.Registries"); + const {_lt} = require("@web/core/l10n/translation"); + + class RefundInfoPopup extends AbstractAwaitablePopup { + constructor() { + super(...arguments); + + this.state = useState({inputValue: this.props.startingValue}); + this.inputRefundReport = useRef("inputRefundReport"); + this.inputRefundDate = useRef("inputRefundDate"); + this.inputRefundDocNum = useRef("inputRefundDocNum"); + this.inputRefundCashFiscalSerial = useRef("inputRefundCashFiscalSerial"); + this.inputRefundFullRefund = useRef("inputRefundFullRefund"); + this.inputDatePicker = this.initializeDatePicker(); + } + + clickConfirmRefund() { + this.$el = $(this.el); + var self = this; + function allValid() { + return self.$el + .find("input") + .not("#refund_full_refund") + .toArray() + .every(function (element) { + return element.value && element.value != ""; + }); + } + + if (allValid()) { + this.$el.find("#error-message-dialog").hide(); + + var refund_date = this.inputRefundDate.el.value; + var refund_report = this.inputRefundReport.el.value; + var refund_doc_num = this.inputRefundDocNum.el.value; + var refund_cash_fiscal_serial = + this.inputRefundCashFiscalSerial.el.value; + var refund_full_refund = this.inputRefundFullRefund.el.checked; + this.env.pos.context = { + refund_details: true, + refund_date: refund_date, + refund_report: refund_report, + refund_doc_num: refund_doc_num, + refund_cash_fiscal_serial: refund_cash_fiscal_serial, + refund_full_refund: refund_full_refund, + }; + this.env.pos.set_refund_data( + refund_date, + refund_report, + refund_doc_num, + refund_cash_fiscal_serial, + refund_full_refund + ); + if ( + this.props.update_refund_info_button && + this.props.update_refund_info_button instanceof Function + ) { + this.props.update_refund_info_button(); + } + this.env.posbus.trigger("close-popup", {popupId: this.props.id}); + } else { + this.$el.find("#error-message-dialog").show(); + } + } + + initializeDatePicker() { + this.$el = $(this.el); + var element = this.$el.find("#refund_date").get(0); + if (element && !this.datepicker) { + // eslint-disable-next-line + this.datepicker = new Pikaday({ + field: element, + }); + } + } + } + + RefundInfoPopup.template = "RefundInfoPopup"; + + RefundInfoPopup.defaultProps = { + confirmText: _lt("Ok"), + cancelText: _lt("Cancel"), + body: "", + }; + + Registries.Component.add(RefundInfoPopup); + + return RefundInfoPopup; +}); diff --git a/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js b/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js new file mode 100644 index 000000000000..ea3124867728 --- /dev/null +++ b/fiscal_epos_print/static/src/js/Screens/PaymentScreen/PaymentScreen.js @@ -0,0 +1,99 @@ +odoo.define("fiscal_epos_print.PaymentScreen", function (require) { + "use strict"; + + var core = require("web.core"); + var epson_epos_print = require("fiscal_epos_print.epson_epos_print"); + var _t = core._t; + var eposDriver = epson_epos_print.eposDriver; + const Registries = require("point_of_sale.Registries"); + const PaymentScreen = require("point_of_sale.PaymentScreen"); + + // eslint-disable-next-line + const MyPaymentScreen = (PaymentScreen) => + class extends PaymentScreen { + setup() { + super.setup(); + if (this.env.pos.config.printer_ip) { + var currentOrder = this.env.pos.get_order(); + var printer_options = currentOrder.getPrinterOptions(); + var fp90 = new eposDriver(printer_options, this); + var amount = this.env.pos.format_currency( + currentOrder.get_total_with_tax() + ); + fp90.printDisplayText(_t("SubTotal") + " " + amount); + } + } + + async sendToFP90Printer(order) { + if (this.env.pos.config.printer_ip && !order.is_to_invoice()) { + // TODO self.chrome does not exists + // this.chrome.loading_show(); + // this.chrome.loading_message(_t('Connecting to the fiscal printer')); + if ( + order.has_refund && + this.env.pos.context && + this.env.pos.context.refund_details + ) { + order.refund_date = this.env.pos.context.refund_date; + order.refund_report = this.env.pos.context.refund_report; + order.refund_doc_num = this.env.pos.context.refund_doc_num; + order.refund_cash_fiscal_serial = + this.env.pos.context.refund_cash_fiscal_serial; + } + + var printer_options = order.getPrinterOptions(); + printer_options.order = order; + var receipt = order.export_for_printing(); + var fp90 = new eposDriver(printer_options, this); + await fp90.printFiscalReceipt(receipt); + await new Promise((resolve) => setTimeout(resolve, 2000)); + // This line causes problems on bill split. What's the sense of deleting the actual pos context?! + // It regenerates orders which are already partly paid using split function... + // this.env.pos.context = {}; + } + } + + async _finalizeValidation() { + var currentOrder = this.currentOrder; + await this.sendToFP90Printer(currentOrder); + await super._finalizeValidation(); + } + + _isOrderValid(isForceValidate) { + if (this.env.pos.config.iface_tax_included === "subtotal") { + this.showPopup("ErrorPopup", { + title: _t("Wrong tax configuration"), + body: _t( + "Product prices on receipts must be set to 'Tax-Included Price' in POS configuration" + ), + }); + return false; + } + var receipt = this.env.pos.get_order(); + if ( + receipt.has_refund && + (receipt.refund_date === null || + receipt.refund_date === "" || + receipt.refund_doc_num === null || + receipt.refund_doc_num === "" || + receipt.refund_cash_fiscal_serial === null || + receipt.refund_cash_fiscal_serial === "" || + receipt.refund_report === null || + receipt.refund_report === "") + ) { + this.showPopup("ErrorPopup", { + title: _t("Refund Information Not Present"), + body: _t( + "The refund information aren't present. Please insert them before printing the receipt" + ), + }); + return false; + } + return super._isOrderValid(isForceValidate); + } + }; + + Registries.Component.extend(PaymentScreen, MyPaymentScreen); + + return PaymentScreen; +}); diff --git a/fiscal_epos_print/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js b/fiscal_epos_print/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js new file mode 100644 index 000000000000..ebf694c75fb1 --- /dev/null +++ b/fiscal_epos_print/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js @@ -0,0 +1,51 @@ +odoo.define("fiscal_epos_print.ReceiptScreen", function (require) { + "use strict"; + + var epson_epos_print = require("fiscal_epos_print.epson_epos_print"); + var eposDriver = epson_epos_print.eposDriver; + const Registries = require("point_of_sale.Registries"); + const ReceiptScreen = require("point_of_sale.ReceiptScreen"); + + // eslint-disable-next-line + const MyReceiptScreen = (ReceiptScreen) => + class extends ReceiptScreen { + lock_screen(locked) { + super.lock_screen(...arguments); + if (locked) { + this.$(".receipt-sent").hide(); + this.$(".printing-error").show(); + this.$(".printing-retry").show(); + } else { + this.$(".receipt-sent").show(); + this.$(".printing-error").hide(); + this.$(".printing-retry").hide(); + } + } + + sendToFP90Printer(receipt, printer_options) { + var fp90 = new eposDriver(printer_options, this); + fp90.printFiscalReceipt(receipt); + } + + render_receipt() { + var self = this; + this._super(); + this.$(".printing-retry").click(function () { + if (self._locked) { + var currentOrder = self.env.pos.get_order(); + // TODO self.chrome does not exists + // self.chrome.loading_show(); + // self.chrome.loading_message(_t('Connecting to the fiscal printer')); + var printer_options = currentOrder.getPrinterOptions(); + printer_options.order = currentOrder; + var receipt = currentOrder.export_for_printing(); + self.sendToFP90Printer(receipt, printer_options); + } + }); + } + }; + + Registries.Component.extend(ReceiptScreen, MyReceiptScreen); + + return ReceiptScreen; +}); diff --git a/fiscal_epos_print/static/src/js/epson_epos_print.js b/fiscal_epos_print/static/src/js/epson_epos_print.js new file mode 100644 index 000000000000..c750a39ff3db --- /dev/null +++ b/fiscal_epos_print/static/src/js/epson_epos_print.js @@ -0,0 +1,828 @@ +odoo.define("fiscal_epos_print.epson_epos_print", function (require) { + "use strict"; + + var core = require("web.core"); + var utils = require("web.utils"); + // Var PosDB = require('point_of_sale.DB'); + // var rpc = require('web.rpc'); + var _t = core._t; + var round_pr = utils.round_precision; + + const {Gui} = require("point_of_sale.Gui"); + + function addPadding(str, padding = 4) { + var pad = new Array(padding).fill(0).join("") + str; + return pad.substr(pad.length - padding, padding); + } + + function isErrorStatus(printerStatus) { + var error = false; + switch (printerStatus.substring(0, 2)) { + case "00": + case "01": + case "20": + case "21": + error = false; + break; + default: + error = true; + } + return error; + } + + // eslint-disable-next-line + function decodeFpStatus(printerStatus) { + var printer = ""; + var ej = ""; + var receipt = ""; + + switch (printerStatus.substring(0, 1)) { + case "0": + printer = false; + break; + case "2": + printer = _t("Paper running low"); + break; + case "3": + printer = _t("Offline (end of paper or open cover)"); + break; + default: + printer = _t("Wrong answer"); + } + + switch (printerStatus.substring(1, 2)) { + case "0": + ej = false; + break; + case "1": + ej = _t("Running low"); + break; + case "2": + ej = _t("To format"); + break; + case "3": + ej = _t("Previous"); + break; + case "4": + ej = _t("From other measurement device"); + break; + case "5": + ej = _t("Finished"); + break; + default: + ej = _t("Wrong answer"); + } + + switch (printerStatus.substring(3, 4)) { + case "0": + receipt = _t("Fiscal open"); + break; + case "1": + receipt = false; + // Receipt = "Fiscale/Non fiscale chiuso"; + break; + case "2": + receipt = _t("Non fiscal open"); + break; + case "3": + receipt = _t("Payment in progress"); + break; + case "4": + receipt = _t( + "Error on last ESC/POS command with Fiscal/Non fiscal closed" + ); + break; + case "5": + receipt = _t("Negative receipt"); + break; + case "6": + receipt = _t("Error on last ESC/POS command with Non fiscal open"); + break; + case "7": + receipt = _t("Waiting for receipt closing in JAVAPOS mode"); + break; + case "8": + receipt = _t("Fiscal document open"); + break; + case "A": + receipt = _t("Title open"); + break; + case "B": + receipt = _t("Title closed"); + break; + default: + receipt = _t("Wrong answer"); + } + + return printer || ej || receipt; + } + + function getStatusField(tag) { + return tag === "printerStatus" || tag === "fsStatus"; + } + + var eposDriver = core.Class.extend({ + init: function (options, sender) { + var self = this; + var opts = options || {}; + this.url = opts.url || "http://192.168.1.1/cgi-bin/fpmate.cgi"; + // eslint-disable-next-line + this.fiscalPrinter = new epson.fiscalPrint(); + this.sender = sender; + this.order = opts.order || null; + // eslint-disable-next-line + this.fiscalPrinter.onreceive = function (res, tag_list_names, add_info) { + // TODO not exist + // sender.chrome.loading_hide(); + var tagStatus = tag_list_names + ? tag_list_names.filter(getStatusField) + : []; + var msgPrinter = ""; + var info = ""; + + if (tagStatus.length > 0 && res.success) { + info = add_info[tagStatus[0]]; + res.success = !isErrorStatus(info); + } + + var order = ""; + if (!res.success) { + if (self.order !== null) { + order = self.order; + order.fiscal_printer_debug_info = + JSON.stringify(res) + + "\n" + + JSON.stringify(tag_list_names) + + "\n" + + JSON.stringify(add_info); + // Sender.env.pos.push_single_order(order); + } + if (tagStatus.length > 0) { + info = add_info[tagStatus[0]]; + msgPrinter = decodeFpStatus(info); + } + // TODO + // sender.chrome.screens['receipt'].lock_screen(true); + // TODO is this correct? + Gui.showPopup("ErrorPopup", { + title: _t("Connection to the printer failed"), + body: + _t( + "An error happened while sending data to the printer. Error code: " + ) + + (res.code || "") + + "\n" + + _t("Error Message: ") + + msgPrinter, + }); + return; + } + + if (add_info.responseCommand === "1138") { + // Coming from FiscalPrinterADEFilesButtonWidget + var to_be_sent = + add_info.responseData[9] + + add_info.responseData[10] + + add_info.responseData[11] + + add_info.responseData[12]; + var old = + add_info.responseData[13] + + add_info.responseData[14] + + add_info.responseData[15] + + add_info.responseData[16]; + var rejected = + add_info.responseData[17] + + add_info.responseData[18] + + add_info.responseData[19] + + add_info.responseData[20]; + var msg = + _t("Files waiting to be sent: ") + + to_be_sent + + "; " + + _t("Old files: ") + + old + + "; " + + _t("Rejected files: ") + + rejected; + // TODO is this correct? + Gui.showPopup("ErrorPopup", { + title: _t("IRA files"), + body: msg, + }); + return; + } + + // Is it a receipt data? + if ( + add_info.fiscalReceiptNumber && + add_info.fiscalReceiptAmount && + add_info.fiscalReceiptDate && + add_info.zRepNumber + ) { + // TODO + // sender.chrome.screens['receipt'].lock_screen(false); + order = self.order; + order._printed = true; + if (!order.fiscal_receipt_number) { + order.fiscal_receipt_number = parseInt( + add_info.fiscalReceiptNumber, + 10 + ); + order.fiscal_receipt_amount = parseFloat( + add_info.fiscalReceiptAmount.replace(",", ".") + ); + var fiscalReceiptDate = new Date( + add_info.fiscalReceiptDate.replace( + /(\d{1,2})\/(\d{1,2})\/(\d{4})/, + "$3/$2/$1" + ) + ); + order.fiscal_receipt_date = + moment(fiscalReceiptDate).format("YYYY-MM-DD"); + order.fiscal_z_rep_number = add_info.zRepNumber; + order.fiscal_printer_serial = + sender.env.pos.config.fiscal_printer_serial; + // Sender.env.pos.db.add_order(order.export_as_JSON()); + // Try to save the order + // sender.env.pos.push_single_order(order); + } + if (sender.env.pos.config.fiscal_cashdrawer) { + self.printOpenCashDrawer(); + self.resetPrinter(); + } + if (!sender.env.pos.config.show_receipt_when_printing) { + // TODO + // sender.chrome.screens['receipt'].click_next(); + } + return; + } + }; + this.fiscalPrinter.onerror = function () { + // TODO not exist + // sender.chrome.loading_hide(); + // sender.chrome.screens['receipt'].lock_screen(true); + // TODO is this correct? + Gui.showPopup("ErrorPopup", { + title: _t("Network error"), + body: _t("Printer can not be reached"), + }); + }; + }, + + encodeXml: function (string) { + var xml_special_to_escaped_one_map = { + "&": "&", + '"': """, + "<": "<", + ">": ">", + }; + + // eslint-disable-next-line + return string.replace(/([\&"<>])/g, function (str, item) { + return xml_special_to_escaped_one_map[item]; + }); + }, + + /* + Prints a sale item line. + */ + printRecItem: function (args) { + var tag = + ""; + return tag; + }, + + /* + Prints a sale refund item line. + */ + printFiscalRefundDetails: function (args) { + var message = + "REFUND " + + addPadding(args.refund_report) + + " " + + addPadding(args.refund_doc_num) + + " " + + // Day + args.refund_date.substr(8, 2) + + // Month + args.refund_date.substr(5, 2) + + // Year + args.refund_date.substr(0, 4) + + " " + + args.refund_cash_fiscal_serial; + + var tag = + ""; + return tag; + }, + + printFiscalVoidDetails: function (args) { + var message = + "VOID " + + addPadding(args.refund_report) + + " " + + addPadding(args.refund_doc_num) + + " " + + // Day + args.refund_date.substr(8, 2) + + // Month + args.refund_date.substr(5, 2) + + // Year + args.refund_date.substr(0, 4) + + " " + + args.refund_cash_fiscal_serial; + + var tag = + ""; + return tag; + }, + + /* + Prints a sale refund item line. + Prints refund items on a commercial refund document if flag SET 14/58 = 1 (from display 3333 > 14 > 58 > X). + */ + printRecRefund: function (args) { + var tag = + ""; + return tag; + }, + + /* + Adds a discount to the last line. + */ + printRecItemAdjustment: function (args) { + var tag = + ""; + return tag; + }, + + /* + Prints a payment. + */ + printRecTotal: function (args) { + var tag = + ""; + return tag; + }, + + printRecTotalRefund: function (args) { + var tag = + ""; + return tag; + }, + + /* + Prints a rounding + */ + printRounding: function (args) { + var tag = + "'; + return tag; + }, + + // Remember that the header goes after + // but before otherwise it will not be printed + // as additional header messageType=1 + printFiscalReceiptHeader: function (receipt) { + var self = this; + var msg = ""; + if (receipt.header !== "" && receipt.header.length > 0) { + var hdr = receipt.header.split(/\r\n|\r|\n/); + _.each(hdr, function (m, i) { + msg += + "'; + }); + } + return msg; + }, + + // Remember that the footer goes within + // as PROMO code messageType=3 + printFiscalReceiptFooter: function (receipt) { + var self = this; + var msg = ""; + if (receipt.footer !== "" && receipt.footer.length > 0) { + var hdr = receipt.footer.split(/\r\n|\r|\n/); + _.each(hdr, function (m, i) { + msg += + "'; + }); + } + return msg; + }, + + printDisplayText: function (msg) { + var xml = + "" + + ""; + this.fiscalPrinter.send(this.url, xml); + }, + + /* + Print the order.id into fiscal receipt for the refund + */ + printOrderId: function (receipt) { + var message = receipt.name; + var tag = + ""; + return tag; + }, + + /* + Prints info payment customer + */ + printInfoPaymentCustomer: function (receipt) { + var tag = + ''; + var index = 5; + _.each(receipt.ticket.split("
"), function (msg) { + index += 1; + tag += + "'; + }); + return tag; + }, + + /* + Prints a receipt + */ + printFiscalReceipt: function (receipt) { + var self = this; + var has_refund = _.every(receipt.orderlines, function (line) { + return line.quantity < 0; + }); + var xml = ""; + var fiscal_operator = receipt.fiscal_operator_number || "1"; + // Header must be printed before beginning a fiscal receipt + if (!receipt.refund_full_refund) { + xml += this.printFiscalReceiptHeader(receipt); + } + if (has_refund) { + if (receipt.refund_full_refund) { + xml += this.printFiscalVoidDetails({ + refund_date: receipt.refund_date, + refund_report: receipt.refund_report, + refund_doc_num: receipt.refund_doc_num, + refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial, + operator: fiscal_operator, + }); + } else { + xml += this.printFiscalRefundDetails({ + refund_date: receipt.refund_date, + refund_report: receipt.refund_report, + refund_doc_num: receipt.refund_doc_num, + refund_cash_fiscal_serial: receipt.refund_cash_fiscal_serial, + operator: fiscal_operator, + }); + } + } + xml += ''; + + _.each(receipt.orderlines, function (l) { + if (l.price >= 0) { + if (l.quantity >= 0) { + if (l.discount < 100) { + xml += self.printRecItem({ + description: l.product_name, + quantity: l.quantity, + unitPrice: round_pr( + l.full_price, + self.sender.env.pos.currency.rounding + ), + department: l.tax_department.code, + operator: fiscal_operator, + }); + if (l.discount) { + xml += self.printRecItemAdjustment({ + adjustmentType: 0, + description: + _t("Discount") + " " + l.discount + "%", + amount: round_pr( + l.quantity * l.full_price - l.price_display, + self.sender.env.pos.currency.rounding + ), + operator: fiscal_operator, + }); + } + } + } else { + xml += self.printRecRefund({ + description: _t("Refund: ") + l.product_name, + quantity: l.quantity * -1.0, + unitPrice: round_pr( + l.price, + self.sender.env.pos.currency.rounding + ), + department: l.tax_department.code, + operator: fiscal_operator, + }); + + // TODO This line of code is added by us, check if it's right + // xml += self.printRecItem({ + // description: _t("Refund cash"), + // quantity: l.quantity, + // unitPrice: round_pr( + // l.price, + // self.sender.env.pos.currency.rounding + // ), + // department: l.tax_department.code, + // operator: fiscal_operator, + // }); + } + } else { + xml += self.printRecItemAdjustment({ + adjustmentType: 3, + description: l.product_name, + department: l.tax_department.code, + amount: -l.price, + operator: fiscal_operator, + }); + } + }); + // Footer can go only as promo code so within a fiscal receipt body + xml += this.printFiscalReceiptFooter(receipt); + if (receipt.lottery_code) { + // TX + // 1 135 OP ID CODE NU + // Example: 113501ABCDEFGN 0000 + // Pad with spaces to make the code field always 16 characters. + xml += + ''; + } + if (receipt.rounding_applied !== 0 && !has_refund) { + xml += self.printRounding({ + amount: Math.abs( + round_pr( + receipt.rounding_applied, + self.sender.env.pos.currency.rounding + ) + ), + operator: fiscal_operator, + }); + xml += + ''; + } + // TODO is always the same Total for refund and payments? + receipt.ticket = ""; + _.each(receipt.paymentlines, function (l) { + // Set ticket + receipt.ticket += l.ticket; + // Amount always positive because it's used for refund too + if (has_refund) { + xml += self.printRecTotalRefund({ + payment: Math.abs(l.amount), + paymentType: l.type, + paymentIndex: l.type_index, + description: l.journal, + operator: fiscal_operator, + }); + } else { + xml += self.printRecTotal({ + payment: Math.abs(l.amount), + paymentType: l.type, + paymentIndex: l.type_index, + description: l.journal, + operator: fiscal_operator, + }); + } + }); + xml += this.printOrderId(receipt); + if (receipt.ticket) { + xml += this.printInfoPaymentCustomer(receipt); + } + xml += + ''; + this.fiscalPrinter.send(this.url, xml); + console.log(xml); + }, + + /* + DON'T USE, this fiscal closure is forbid by Epson by default + */ + printFiscalReport: function (f_op) { + var xml = ""; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + + /* + It prints report and fiscal closure both + */ + printFiscalXZReport: function (f_op) { + var xml = ""; + xml += + ''; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + + printFiscalXReport: function (f_op) { + var xml = ""; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + + getStatusOfFilesForADE: function () { + var xml = ""; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + + /* + It need to be logged in to print the duplicate, the pw in data is 0212345 plus 93 spaces, total 100 chars + */ + printFiscalReprintLast: function (f_op) { + var xml = ""; + xml += + ''; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + + printOpenCashDrawer: function () { + var xml = ""; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + + resetPrinter: function () { + var xml = ""; + xml += ''; + xml += ''; + xml += ""; + this.fiscalPrinter.send(this.url, xml); + }, + }); + + return { + eposDriver: eposDriver, + }; +}); diff --git a/fiscal_epos_print/static/src/js/models.js b/fiscal_epos_print/static/src/js/models.js new file mode 100644 index 000000000000..fe22148d2f70 --- /dev/null +++ b/fiscal_epos_print/static/src/js/models.js @@ -0,0 +1,285 @@ +odoo.define("fiscal_epos_print.models", function (require) { + "use strict"; + + var {PosGlobalState, Order, Orderline, Payment} = require("point_of_sale.models"); + const {Gui} = require("point_of_sale.Gui"); + var core = require("web.core"); + var _t = core._t; + const Registries = require("point_of_sale.Registries"); + + const FiscalEposPrintPosGlobalState = (PosGlobalState) => + class FiscalEposPrintPosGlobalState extends PosGlobalState { + set_refund_data( + refund_date, + refund_report, + refund_doc_num, + refund_cash_fiscal_serial, + refund_full_refund + ) { + const selectedOrder = this.get_order(); + selectedOrder.refund_date = refund_date; + selectedOrder.refund_report = refund_report; + selectedOrder.refund_doc_num = refund_doc_num; + selectedOrder.refund_cash_fiscal_serial = refund_cash_fiscal_serial; + selectedOrder.refund_full_refund = refund_full_refund; + } + + set_lottery_code_data(lottery_code) { + const selectedOrder = this.get_order(); + selectedOrder.lottery_code = lottery_code; + } + + reset_cashier() { + this.cashier = { + name: null, + id: null, + barcode: null, + user_id: null, + pin: null, + role: null, + fiscal_operator_number: null, + }; + } + }; + Registries.Model.extend(PosGlobalState, FiscalEposPrintPosGlobalState); + + const FiscalEposPrintOrder = (Order) => + class FiscalEposPrintOrder extends Order { + constructor() { + super(...arguments); + this.lottery_code = null; + this.refund_report = null; + this.refund_date = null; + this.refund_doc_num = null; + this.refund_cash_fiscal_serial = null; + this.refund_full_refund = false; + this.has_refund = false; + this.fiscal_receipt_number = null; + this.fiscal_receipt_amount = null; + this.fiscal_receipt_date = null; + this.fiscal_z_rep_number = null; + this.fiscal_printer_serial = + this.pos.config.fiscal_printer_serial || null; + this.fiscal_printer_debug_info = null; + try { + if (this.pos.config.module_pos_hr) { + this.fiscal_operator_number = + this.pos.cashier.fiscal_operator_number || null; + } else { + this.fiscal_operator_number = "1"; + } + } catch (error) { + this.fiscal_operator_number = "1"; + } + } + + // Manages the case in which after printing an invoice + // you pass a barcode in the mask of the registered invoice + add_product(product, options) { + if (this._printed || this.finalized === true) { + this.destroy(); + return this.pos.get_order().add_product(product, options); + } + return super.add_product(...arguments); + } + + check_order_has_refund() { + var order = this.pos.get_order(); + if (order) { + var lines = order.orderlines; + order.has_refund = + lines.find(function (line) { + return line.quantity < 0.0; + }) !== undefined; + if (order.has_refund) { + order.refund_report = this.name.substr(-4); + order.refund_doc_num = this.name.substr(-4); + order.refund_date = new Date(); + order.refund_cash_fiscal_serial = + this.pos.config.fiscal_printer_serial; + } + } + } + + init_from_JSON(json) { + super.init_from_JSON(...arguments); + this.check_order_has_refund(); + this.lottery_code = json.lottery_code; + this.refund_report = json.refund_report; + this.refund_date = json.refund_date; + this.refund_doc_num = json.refund_doc_num; + this.refund_cash_fiscal_serial = json.refund_cash_fiscal_serial; + this.refund_full_refund = json.refund_full_refund; + this.fiscal_receipt_number = json.fiscal_receipt_number; + this.fiscal_receipt_amount = json.fiscal_receipt_amount; + this.fiscal_receipt_date = json.fiscal_receipt_date; + this.fiscal_z_rep_number = json.fiscal_z_rep_number; + this.fiscal_printer_serial = this.pos.config.fiscal_printer_serial; + this.fiscal_printer_debug_info = json.fiscal_printer_debug_info; + try { + if (this.pos.config.module_pos_hr && json.employee_id) { + this.fiscal_operator_number = + this.pos.employee_by_id[json.employee_id] + .fiscal_operator_number || null; + } else { + this.fiscal_operator_number = "1"; + } + } catch (error) {} + } + + export_as_JSON() { + const json = super.export_as_JSON(...arguments); + this.check_order_has_refund(); + json.lottery_code = this.lottery_code || null; + json.refund_report = this.refund_report || null; + json.refund_date = this.refund_date || null; + json.refund_doc_num = this.refund_doc_num || null; + json.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial || null; + json.refund_full_refund = this.refund_full_refund || false; + json.fiscal_receipt_number = this.fiscal_receipt_number || null; + json.fiscal_receipt_amount = this.fiscal_receipt_amount || null; + // Parsed by backend + json.fiscal_receipt_date = this.fiscal_receipt_date || null; + json.fiscal_z_rep_number = this.fiscal_z_rep_number || null; + json.fiscal_printer_serial = this.fiscal_printer_serial || null; + json.fiscal_printer_debug_info = this.fiscal_printer_debug_info || null; + try { + if (this.pos.config.module_pos_hr) { + json.fiscal_operator_number = + this.pos.cashier.fiscal_operator_number || null; + } else { + json.fiscal_operator_number = "1"; + } + } catch (error) {} + return json; + } + + export_for_printing() { + var json = super.export_for_printing(...arguments); + json.lottery_code = this.lottery_code; + json.refund_date = this.refund_date; + json.refund_report = this.refund_report; + json.refund_doc_num = this.refund_doc_num; + json.refund_cash_fiscal_serial = this.refund_cash_fiscal_serial; + json.refund_full_refund = this.refund_full_refund; + json.fiscal_receipt_number = this.fiscal_receipt_number; + json.fiscal_receipt_amount = this.fiscal_receipt_amount; + json.fiscal_receipt_date = this.fiscal_receipt_date; + json.fiscal_z_rep_number = this.fiscal_z_rep_number; + json.fiscal_printer_serial = this.fiscal_printer_serial; + json.fiscal_printer_debug_info = this.fiscal_printer_debug_info; + try { + json.fiscal_operator_number = + this.pos.cashier.fiscal_operator_number || null; + } catch (error) {} + return json; + } + + getPrinterOptions() { + var protocol = this.pos.config.use_https ? "https://" : "http://"; + var printer_url = + protocol + this.pos.config.printer_ip + "/cgi-bin/fpmate.cgi"; + return {url: printer_url}; + } + }; + Registries.Model.extend(Order, FiscalEposPrintOrder); + + const FiscalEposPrintOrderline = (Orderline) => + class FiscalEposPrintOrderline extends Orderline { + export_for_printing() { + var receipt = super.export_for_printing(...arguments); + + receipt.tax_department = this.get_tax_details_r(); + if (!receipt.tax_department) { + Gui.showPopup("ErrorPopup", { + title: _t("Network error"), + body: _t("Manca iva su prodotto"), + }); + } + if (receipt.tax_department) { + if (receipt.tax_department.included_in_price === true) { + receipt.full_price = this.price; + } else { + // This strategy was used because JavaScript's Math.round rounds to the nearest integer + const dec_precision = this.pos.currency.decimal_places; + const full_price = Number( + ( + this.price * + (1 + receipt.tax_department.tax_amount / 100) + ).toFixed(dec_precision) + ); + const rounding_factor = Math.pow(10, dec_precision); + receipt.full_price = + Math.trunc(full_price * rounding_factor) / rounding_factor; + } + } + + return receipt; + } + + get_tax_details_r() { + var detail = this.get_all_prices().taxDetails; + for (var i in detail) { + return { + code: this.pos.taxes_by_id[i].fpdeptax, + taxname: this.pos.taxes_by_id[i].name, + included_in_price: this.pos.taxes_by_id[i].price_include, + tax_amount: this.pos.taxes_by_id[i].amount, + }; + } + // TODO is this correct? + Gui.showPopup("ErrorPopup", { + title: _t("Error"), + body: _t("No taxes found"), + }); + } + + set_quantity(quantity) { + if (quantity === "0") { + // Epson FP doesn't allow lines with quantity 0 + quantity = "remove"; + } + return super.set_quantity(...arguments); + } + }; + Registries.Model.extend(Orderline, FiscalEposPrintOrderline); + + /* + Overwrite Payment.export_for_printing() in order + to make it export the payment type that must be passed + to the fiscal printer. + */ + const FiscalEposPrintPayment = (Payment) => + class FiscalEposPrintPayment extends Payment { + constructor() { + super(...arguments); + this.type = this.payment_method.fiscalprinter_payment_type || null; + this.type_index = + this.payment_method.fiscalprinter_payment_index || null; + } + export_as_JSON() { + const json = super.export_as_JSON(...arguments); + json.type = this.payment_method.fiscalprinter_payment_type; + json.type_index = this.payment_method.fiscalprinter_payment_index; + return json; + } + init_from_JSON(json) { + super.init_from_JSON(...arguments); + this.type = json.type; + this.type_index = json.type_index; + } + setFiscalprinterType(value) { + this.type = value; + } + setFiscalprinterIdex(value) { + this.type_index = value; + } + export_for_printing() { + const res = super.export_for_printing(...arguments); + res.type = this.type; + res.type_index = this.type_index; + return res; + } + }; + Registries.Model.extend(Payment, FiscalEposPrintPayment); +}); diff --git a/fiscal_epos_print/static/src/js/popups.js b/fiscal_epos_print/static/src/js/popups.js new file mode 100644 index 000000000000..7495b813896f --- /dev/null +++ b/fiscal_epos_print/static/src/js/popups.js @@ -0,0 +1,120 @@ +odoo.define("fiscal_epos_print.popups", function (require) { + "use strict"; + + var popups = require("point_of_sale.popups"); + var gui = require("point_of_sale.Gui"); + + // Function addPadding(str, padding = 4) { + // var pad = new Array(padding).fill(0).join("") + str; + // return pad.substr(pad.length - padding, padding); + // } + + var RefundInfoPopupWidget = popups.extend({ + template: "RefundInfoPopupWidget", + init: function (parent) { + this.refund_report = null; + this.refund_date = null; + this.refund_doc_num = null; + this.refund_cash_fiscal_serial = null; + this.datepicker = null; + return this._super(parent); + }, + show: function (options) { + var opts = options || {}; + this._super(opts); + this.update_refund_info_button = opts.update_refund_info_button; + this.renderElement(); + this.datepicker = null; + this.$("refund_report").focus(); + this.initializeDatePicker(); + }, + click_confirm: function () { + var self = this; + function allValid() { + return self + .$("input") + .toArray() + .every(function (element) { + return element.value && element.value !== ""; + }); + } + + if (allValid()) { + this.$("#error-message-dialog").hide(); + + var order = this.pos.get_order(); + order.refund_report = this.$("#refund_report").val(); + order.refund_date = this.$("#refund_date").val(); + order.refund_doc_num = this.$("#refund_doc_num").val(); + order.refund_cash_fiscal_serial = this.$( + "#refund_cash_fiscal_serial" + ).val(); + this.gui.close_popup(); + if ( + this.update_refund_info_button && + this.update_refund_info_button instanceof Function + ) { + this.update_refund_info_button(); + } + } else { + this.$("#error-message-dialog").show(); + } + }, + initializeDatePicker: function () { + var element = this.$("#refund_date").get(0); + + if (element && !this.datepicker) { + // eslint-disable-next-line + this.datepicker = new Pikaday({ + field: element, + }); + } + }, + }); + + var LotteryCodePopupWidget = popups.extend({ + template: "LotteryCodePopupWidget", + init: function (parent) { + this.lottery_code = null; + return this._super(parent); + }, + show: function (options) { + var opts = options || {}; + this._super(opts); + this.update_lottery_info_button = opts.update_lottery_info_button; + this.renderElement(); + this.$("#lottery_code").focus(); + }, + // TODO automatically close popup on barcode scanned + click_confirm: function () { + var self = this; + function allValid() { + return self + .$("input") + .toArray() + .every(function (element) { + return element.value && element.value !== ""; + }); + } + + if (allValid()) { + this.$("#lottery-error-message-dialog").hide(); + + var order = this.pos.get_order(); + order.lottery_code = this.$("#lottery_code").val(); + this.gui.close_popup(); + if ( + this.update_lottery_info_button && + this.update_lottery_info_button instanceof Function + ) { + this.update_lottery_info_button(); + } + } else { + this.$("#lottery-error-message-dialog").show(); + } + }, + }); + + gui.define_popup({name: "refundinfo", widget: RefundInfoPopupWidget}); + gui.define_popup({name: "lotterycode", widget: LotteryCodePopupWidget}); +}); diff --git a/fiscal_epos_print/static/src/js/pos_order_mgmt.js b/fiscal_epos_print/static/src/js/pos_order_mgmt.js new file mode 100644 index 000000000000..edfc1154eab0 --- /dev/null +++ b/fiscal_epos_print/static/src/js/pos_order_mgmt.js @@ -0,0 +1,60 @@ +// TODO is this necessary? +odoo.define("fiscal_epos_print.pos_order_mgmt", function (require) { + "use strict"; + + var core = require("web.core"); + var pos_order_mgmt = require("pos_order_mgmt.widgets"); + var epson_epos_print = require("fiscal_epos_print.epson_epos_print"); + var _t = core._t; + var OrderListScreenWidget = pos_order_mgmt.OrderListScreenWidget; + var eposDriver = epson_epos_print.eposDriver; + + OrderListScreenWidget.include({ + _prepare_order_from_order_data: function (order_data, action) { + var order = this._super(order_data, action); + if (action === "print") { + order.lottery_code = order_data.lottery_code; + order.refund_report = order_data.refund_report; + order.refund_date = order_data.refund_date; + order.refund_doc_num = order_data.refund_doc_num; + order.refund_cash_fiscal_serial = order_data.refund_cash_fiscal_serial; + order.refund_full_refund = order_data.refund_full_refund; + } else if (action === "return") { + order.lottery_code = order_data.lottery_code; + order.refund_report = order_data.fiscal_z_rep_number; + order.refund_date = order_data.fiscal_receipt_date; + order.refund_doc_num = order_data.fiscal_receipt_number; + order.refund_cash_fiscal_serial = order_data.fiscal_printer_serial; + order.refund_full_refund = order_data.refund_full_refund; + } + // For action === 'copy' we don't need to do anything + return order; + }, + // Copiato da screens.PaymentScreenWidget + sendToFP90Printer: function (receipt, printer_options) { + var fp90 = new eposDriver(printer_options, this); + fp90.printFiscalReceipt(receipt); + }, + action_print: function (order_data, order) { + if (this.pos.config.printer_ip) { + if (order_data.fiscal_receipt_number) { + this.pos.gui.show_popup("error", { + title: _t("Order already printed"), + body: + order_data.pos_reference + + _t(": order already has a fiscal number, ") + + order_data.fiscal_receipt_number, + }); + return; + } + this.chrome.loading_show(); + this.chrome.loading_message(_t("Connecting to the fiscal printer")); + var receipt = order.export_for_printing(); + var printer_options = order.getPrinterOptions(); + printer_options.order = order; + this.sendToFP90Printer(receipt, printer_options); + } + return this._super(order_data, order); + }, + }); +}); diff --git a/fiscal_epos_print/static/src/xml/Chrome.xml b/fiscal_epos_print/static/src/xml/Chrome.xml new file mode 100644 index 000000000000..1a27399f1fd5 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/Chrome.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml b/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml new file mode 100644 index 000000000000..7b7c5db2b60d --- /dev/null +++ b/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonEPOSButton.xml @@ -0,0 +1,14 @@ + + + + +
+ Epson ePOS +
+
+ +
diff --git a/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml b/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml new file mode 100644 index 000000000000..062c54008b28 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/ChromeWidgets/EpsonFP81IIComponent.xml @@ -0,0 +1,113 @@ + + + + +
+

Epson ePOS

+ +
+ +
+ +
+

Operations

+
    +
  • +
    + + Open CashDrawer + + + Open CashDrawer + +
    +
  • +
  • +
    + + Reprint Last Receipt + + + Reprint Last Receipt + +
    +
  • +
+

Reports

+
    +
  • +
    + + IRA status + + + IRA status + +
    +
  • +
  • +
    + + Fiscal closure + + + Closure Report Z (Fiscal) + +
    +
  • +
  • +
    + + Fiscal closure + + + Financial Report X + +
    +
  • +
+
+
+
+ +
diff --git a/fiscal_epos_print/static/src/xml/ChromeWidgets/SetLotteryCodeButton.xml b/fiscal_epos_print/static/src/xml/ChromeWidgets/SetLotteryCodeButton.xml new file mode 100644 index 000000000000..1998551cee6c --- /dev/null +++ b/fiscal_epos_print/static/src/xml/ChromeWidgets/SetLotteryCodeButton.xml @@ -0,0 +1,15 @@ + + + + +
+ + Lottery Code +
+
+ +
diff --git a/fiscal_epos_print/static/src/xml/ChromeWidgets/SetRefundInfoButton.xml b/fiscal_epos_print/static/src/xml/ChromeWidgets/SetRefundInfoButton.xml new file mode 100644 index 000000000000..fded09a0246c --- /dev/null +++ b/fiscal_epos_print/static/src/xml/ChromeWidgets/SetRefundInfoButton.xml @@ -0,0 +1,11 @@ + + + + +
+ + Refund Data +
+
+ +
diff --git a/fiscal_epos_print/static/src/xml/ChromeWidgets/SetReprintButton.xml b/fiscal_epos_print/static/src/xml/ChromeWidgets/SetReprintButton.xml new file mode 100644 index 000000000000..7f3f472749e8 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/ChromeWidgets/SetReprintButton.xml @@ -0,0 +1,23 @@ + + + + + +
+
+ + Ristampa Ultimo Scontrino +
+
+
+
+ +
diff --git a/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml b/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml new file mode 100644 index 000000000000..fbba2ca6e392 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/Popups/LotteryCodePopup.xml @@ -0,0 +1,42 @@ + + + + + + + + + + diff --git a/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml b/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml new file mode 100644 index 000000000000..fe10d84ceee9 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/Popups/RefundInfoPopup.xml @@ -0,0 +1,87 @@ + + + + + + + + + + diff --git a/fiscal_epos_print/static/src/xml/lottery.xml b/fiscal_epos_print/static/src/xml/lottery.xml new file mode 100644 index 000000000000..9dd3499334e2 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/lottery.xml @@ -0,0 +1,39 @@ + + + + + + + diff --git a/fiscal_epos_print/static/src/xml/pos.xml b/fiscal_epos_print/static/src/xml/pos.xml new file mode 100644 index 000000000000..5512c12933f8 --- /dev/null +++ b/fiscal_epos_print/static/src/xml/pos.xml @@ -0,0 +1,27 @@ + + + + + +
+ Receipt sent to the printer +
+
+ Invoice recorded +
+ + +
+
+ + + + display:none + + + +
diff --git a/fiscal_epos_print/views/account.xml b/fiscal_epos_print/views/account.xml new file mode 100644 index 000000000000..4a884b74dfad --- /dev/null +++ b/fiscal_epos_print/views/account.xml @@ -0,0 +1,32 @@ + + + + + POS Journal - Fiscal Printer field + pos.payment.method + + + + + + + + + + + + + account.tax.printer.form.view + account.tax + + + + + + + + + diff --git a/fiscal_epos_print/views/employee_view.xml b/fiscal_epos_print/views/employee_view.xml new file mode 100644 index 000000000000..b6d4bed75c49 --- /dev/null +++ b/fiscal_epos_print/views/employee_view.xml @@ -0,0 +1,14 @@ + + + + HR Employee - Fiscal Printer field + hr.employee + + + + + + + + + diff --git a/fiscal_epos_print/views/point_of_sale.xml b/fiscal_epos_print/views/point_of_sale.xml new file mode 100644 index 000000000000..e19b912918b5 --- /dev/null +++ b/fiscal_epos_print/views/point_of_sale.xml @@ -0,0 +1,161 @@ + + + + + pos.config.form.view + pos.config + + + +

Fiscal printer

+
+
+
+ Printer address +
+ The hostname or IP address of the fiscal printer +
+
+ +
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ Fiscal Printer Serial +
+ +
+
+
+
+
+
+
+ + + res.config.settings.form.printer.view + res.config.settings + + +

+

Fiscal printer

+
+
+
+ Printer address +
+ The hostname or IP address of the fiscal printer +
+
+ +
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ Fiscal Printer Serial +
+ +
+
+
+
+ +
+
+ + + pos.order.form + pos.order + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/l10n_it_asset_management/README.rst b/l10n_it_asset_management/README.rst index fd096a46402d..85c7af87ccd3 100644 --- a/l10n_it_asset_management/README.rst +++ b/l10n_it_asset_management/README.rst @@ -7,7 +7,7 @@ ITA - Gestione Cespiti !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:5c523a2684aa69e490e6fe09e1700c382ee33ce9c9d69c1d1a7b66d4a454ec23 + !! source digest: sha256:61b720888e8c18d6974ba493322d56acd2195125d900de1fc6c85f9069c7e5df !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/l10n_it_asset_management/__manifest__.py b/l10n_it_asset_management/__manifest__.py index 518aaeaf6b5d..7caf1adb439d 100644 --- a/l10n_it_asset_management/__manifest__.py +++ b/l10n_it_asset_management/__manifest__.py @@ -5,7 +5,7 @@ { "name": "ITA - Gestione Cespiti", - "version": "16.0.1.0.1", + "version": "16.0.1.3.0", "category": "Localization/Italy", "summary": "Gestione Cespiti", "author": "Openforce, Odoo Community Association (OCA)", diff --git a/l10n_it_asset_management/data/asset_data.xml b/l10n_it_asset_management/data/asset_data.xml index 44305f64ea84..3eb1ed340c1a 100644 --- a/l10n_it_asset_management/data/asset_data.xml +++ b/l10n_it_asset_management/data/asset_data.xml @@ -37,8 +37,8 @@ - 1 - 1 + 1 + 1 0.5 diff --git a/l10n_it_asset_management/i18n/it.po b/l10n_it_asset_management/i18n/it.po index 98b186839091..e28474d303e9 100644 --- a/l10n_it_asset_management/i18n/it.po +++ b/l10n_it_asset_management/i18n/it.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-12-23 08:16+0000\n" -"PO-Revision-Date: 2024-09-27 09:06+0000\n" +"PO-Revision-Date: 2024-10-05 17:06+0000\n" "Last-Translator: mymage \n" "Language-Team: \n" "Language: it\n" @@ -24,6 +24,11 @@ msgstr "" msgid "%(year)s - Depreciation" msgstr "%(year)s - Ammortamento" +#. module: l10n_it_asset_management +#: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.wizard_asset_generate_depreciation_form_view +msgid "" +msgstr "" + #. module: l10n_it_asset_management #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.template_asset_journal_body #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.template_asset_previsional_body @@ -976,6 +981,7 @@ msgstr "Plusvalenza" #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_category__gain_account_id +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__gain_account_id msgid "Capital Gain Account" msgstr "Conto plusvalenza" @@ -987,6 +993,7 @@ msgstr "Minusvalenza" #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_category__loss_account_id +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__loss_account_id msgid "Capital Loss Account" msgstr "Conto minusvalenza" @@ -1142,6 +1149,12 @@ msgstr "Crea cespite e mostra" msgid "Create New" msgstr "Crea nuovo" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_wizard_asset_generate_depreciation__journal_id +msgid "Create move entries in this journal instead of the category's journal." +msgstr "" +"Crea voci movimento in questo registro anziché nel registro della categoria." + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_accounting_info__create_uid #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_asset__create_uid @@ -1383,8 +1396,9 @@ msgstr "Amm. (%)" #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_category__depreciation_account_id +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__depreciation_account_id msgid "Depreciation Account" -msgstr "Fondo amm.to" +msgstr "Conto amm.to" #. module: l10n_it_asset_management #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.wizard_asset_generate_depreciation_form_view @@ -1703,9 +1717,9 @@ msgid "Force First Dep. Num" msgstr "Forza primo numero amm.to" #. module: l10n_it_asset_management -#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__from_nr -msgid "From Nr" -msgstr "Dal n°" +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__from_year_nr +msgid "From Year" +msgstr "Dall'anno" #. module: l10n_it_asset_management #. odoo-python @@ -2112,21 +2126,49 @@ msgstr "Gestione cespiti da movimenti conto" msgid "Management Type" msgstr "Tipo gestione" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_asset_depreciation_mode_line__to_year_nr +msgid "" +"Maximum number of fiscal years passed from asset purchase date to apply this " +"line." +msgstr "" +"Numero massimo di anni fiscali trascorsi dalla data di acquisto del cespite " +"per applicare questa riga." + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_asset__message_has_error msgid "Message Delivery error" msgstr "Errore di consegna messaggio" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_wizard_asset_generate_depreciation__missing_fiscal_year_warning +msgid "Message to warn the user that some fiscal years are missing." +msgstr "Messaggio per avvisare l'utente che mancano alcuni anni fiscali." + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_asset__message_ids msgid "Messages" msgstr "Messaggi" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_asset_depreciation_mode_line__from_year_nr +msgid "" +"Minimum number of fiscal years passed from asset purchase date to apply this " +"line." +msgstr "" +"Numero minimo di anni fiscali trascorsi dalla data di acquisto del cespite " +"per applicare questa riga." + #. module: l10n_it_asset_management #: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_account_move_manage_asset__move_type__general msgid "Miscellaneous" msgstr "Varie" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__missing_fiscal_year_warning +msgid "Missing Fiscal Year Warning" +msgstr "Avviso anno fiscale mancante" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__mode_id #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__mode_id @@ -2139,6 +2181,11 @@ msgstr "Modo" msgid "Mode Name" msgstr "Nome modo" +#. module: l10n_it_asset_management +#: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_asset_generate_depreciation__period__month +msgid "Month" +msgstr "Mese" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_accounting_info__move_id #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_line__move_id @@ -2282,6 +2329,11 @@ msgstr "Numero di messaggi che richiedono un'azione" msgid "Number of messages with delivery error" msgstr "Numero di messaggi con errore di consegna" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__period_count +msgid "Number of periods" +msgstr "Numero di periodi" + #. module: l10n_it_asset_management #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.wizard_account_move_mange_asset_form_view msgid "" @@ -2322,6 +2374,11 @@ msgstr "Valore rettifica negativa" msgid "Out Amount - Detail" msgstr "Importo rettifica negativa - Dettaglio" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__journal_id +msgid "Override journal" +msgstr "Ignora registro" + #. module: l10n_it_asset_management #: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_account_move_manage_asset__management_type__partial_dismiss msgid "Partial Dismiss" @@ -2389,6 +2446,11 @@ msgstr "P.IVA partner" msgid "Percentage" msgstr "Percentuale" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__period +msgid "Period" +msgstr "Periodo" + #. module: l10n_it_asset_management #. odoo-python #: code:addons/l10n_it_asset_management/wizard/account_move_manage_asset.py:0 @@ -2822,6 +2884,20 @@ msgstr "Venduto" msgid "Sold assets: show" msgstr "Cespiti vendiuti: visualizza" +#. module: l10n_it_asset_management +#. odoo-python +#: code:addons/l10n_it_asset_management/wizard/asset_generate_depreciation.py:0 +#, python-format +msgid "" +"Some years between %(asset_date)s and %(depreciation_date)s have no " +"configured fiscal year and will not be counted for depreciation.\n" +"Please configure every fiscal year that has to be counted for depreciation." +msgstr "" +"Alcuni anni tra %(asset_date)s e %(depreciation_date)s non hanno un anno " +"fiscale configurato e non saranno conteggiati per l'ammortamento.\n" +"Si prega di configurare ogni anno fiscale che deve essere conteggiato per " +"l'ammortamento." + #. module: l10n_it_asset_management #. odoo-python #: code:addons/l10n_it_asset_management/report/asset_journal_xlsx.py:0 @@ -2920,9 +2996,9 @@ msgid "To Date" msgstr "Alla data" #. module: l10n_it_asset_management -#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__to_nr -msgid "To Nr" -msgstr "Al n°" +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__to_year_nr +msgid "To Year" +msgstr "All'anno" #. module: l10n_it_asset_management #. odoo-python @@ -3086,6 +3162,7 @@ msgstr "Errato" #: code:addons/l10n_it_asset_management/report/asset_previsional_xlsx.py:0 #: model:ir.model.fields,field_description:l10n_it_asset_management.field_report_asset_journal_depreciation_line_year__year #: model:ir.model.fields,field_description:l10n_it_asset_management.field_report_asset_previsional_depreciation_line_year__year +#: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_asset_generate_depreciation__period__year #, python-format msgid "Year" msgstr "Anno" @@ -3196,6 +3273,12 @@ msgstr "o" msgid "to date %(to_date)s" msgstr "alla data %(to_date)s" +#~ msgid "From Nr" +#~ msgstr "Dal n°" + +#~ msgid "To Nr" +#~ msgstr "Al n°" + #, python-format #~ msgid "" #~ "Could not retrieve depreciation line type from move `%(move_num)s` (type " diff --git a/l10n_it_asset_management/i18n/l10n_it_asset_management.pot b/l10n_it_asset_management/i18n/l10n_it_asset_management.pot index f935cd23ec21..16dbe6065958 100644 --- a/l10n_it_asset_management/i18n/l10n_it_asset_management.pot +++ b/l10n_it_asset_management/i18n/l10n_it_asset_management.pot @@ -20,6 +20,11 @@ msgstr "" msgid "%(year)s - Depreciation" msgstr "" +#. module: l10n_it_asset_management +#: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.wizard_asset_generate_depreciation_form_view +msgid "" +msgstr "" + #. module: l10n_it_asset_management #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.template_asset_journal_body #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.template_asset_previsional_body @@ -936,6 +941,7 @@ msgstr "" #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_category__gain_account_id +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__gain_account_id msgid "Capital Gain Account" msgstr "" @@ -947,6 +953,7 @@ msgstr "" #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_category__loss_account_id +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__loss_account_id msgid "Capital Loss Account" msgstr "" @@ -1091,6 +1098,11 @@ msgstr "" msgid "Create New" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_wizard_asset_generate_depreciation__journal_id +msgid "Create move entries in this journal instead of the category's journal." +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_accounting_info__create_uid #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_asset__create_uid @@ -1331,6 +1343,7 @@ msgstr "" #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_category__depreciation_account_id +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__depreciation_account_id msgid "Depreciation Account" msgstr "" @@ -1648,8 +1661,8 @@ msgid "Force First Dep. Num" msgstr "" #. module: l10n_it_asset_management -#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__from_nr -msgid "From Nr" +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__from_year_nr +msgid "From Year" msgstr "" #. module: l10n_it_asset_management @@ -2063,21 +2076,45 @@ msgstr "" msgid "Management Type" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_asset_depreciation_mode_line__to_year_nr +msgid "" +"Maximum number of fiscal years passed from asset purchase date to apply this" +" line." +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_asset__message_has_error msgid "Message Delivery error" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_wizard_asset_generate_depreciation__missing_fiscal_year_warning +msgid "Message to warn the user that some fiscal years are missing." +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_asset__message_ids msgid "Messages" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,help:l10n_it_asset_management.field_asset_depreciation_mode_line__from_year_nr +msgid "" +"Minimum number of fiscal years passed from asset purchase date to apply this" +" line." +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_account_move_manage_asset__move_type__general msgid "Miscellaneous" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__missing_fiscal_year_warning +msgid "Missing Fiscal Year Warning" +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation__mode_id #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__mode_id @@ -2090,6 +2127,11 @@ msgstr "" msgid "Mode Name" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_asset_generate_depreciation__period__month +msgid "Month" +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_accounting_info__move_id #: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_line__move_id @@ -2233,6 +2275,11 @@ msgstr "" msgid "Number of messages with delivery error" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__period_count +msgid "Number of periods" +msgstr "" + #. module: l10n_it_asset_management #: model_terms:ir.ui.view,arch_db:l10n_it_asset_management.wizard_account_move_mange_asset_form_view msgid "" @@ -2272,6 +2319,11 @@ msgstr "" msgid "Out Amount - Detail" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__journal_id +msgid "Override journal" +msgstr "" + #. module: l10n_it_asset_management #: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_account_move_manage_asset__management_type__partial_dismiss msgid "Partial Dismiss" @@ -2340,6 +2392,11 @@ msgstr "" msgid "Percentage" msgstr "" +#. module: l10n_it_asset_management +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_wizard_asset_generate_depreciation__period +msgid "Period" +msgstr "" + #. module: l10n_it_asset_management #. odoo-python #: code:addons/l10n_it_asset_management/wizard/account_move_manage_asset.py:0 @@ -2778,6 +2835,15 @@ msgstr "" msgid "Sold assets: show" msgstr "" +#. module: l10n_it_asset_management +#. odoo-python +#: code:addons/l10n_it_asset_management/wizard/asset_generate_depreciation.py:0 +#, python-format +msgid "" +"Some years between %(asset_date)s and %(depreciation_date)s have no configured fiscal year and will not be counted for depreciation.\n" +"Please configure every fiscal year that has to be counted for depreciation." +msgstr "" + #. module: l10n_it_asset_management #. odoo-python #: code:addons/l10n_it_asset_management/report/asset_journal_xlsx.py:0 @@ -2871,8 +2937,8 @@ msgid "To Date" msgstr "" #. module: l10n_it_asset_management -#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__to_nr -msgid "To Nr" +#: model:ir.model.fields,field_description:l10n_it_asset_management.field_asset_depreciation_mode_line__to_year_nr +msgid "To Year" msgstr "" #. module: l10n_it_asset_management @@ -3038,6 +3104,7 @@ msgstr "" #: code:addons/l10n_it_asset_management/report/asset_previsional_xlsx.py:0 #: model:ir.model.fields,field_description:l10n_it_asset_management.field_report_asset_journal_depreciation_line_year__year #: model:ir.model.fields,field_description:l10n_it_asset_management.field_report_asset_previsional_depreciation_line_year__year +#: model:ir.model.fields.selection,name:l10n_it_asset_management.selection__wizard_asset_generate_depreciation__period__year #, python-format msgid "Year" msgstr "" diff --git a/l10n_it_asset_management/migrations/16.0.1.1.0/pre-migrate.py b/l10n_it_asset_management/migrations/16.0.1.1.0/pre-migrate.py new file mode 100644 index 000000000000..7ba7638b0ef0 --- /dev/null +++ b/l10n_it_asset_management/migrations/16.0.1.1.0/pre-migrate.py @@ -0,0 +1,32 @@ +# Copyright 2024 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from openupgradelib import openupgrade + +MODEL_TO_RENAMED_FIELDS = { + "asset.depreciation.mode.line": [ + ("from_nr", "from_year_nr"), + ("to_nr", "to_year_nr"), + ] +} + + +def _rename_fields(env): + openupgrade.rename_fields( + env, + [ + ( + model_name, + model_name.replace(".", "_"), + field_spec[0], + field_spec[1], + ) + for model_name, field_specs in MODEL_TO_RENAMED_FIELDS.items() + for field_spec in field_specs + ], + ) + + +@openupgrade.migrate() +def migrate(env, version): + _rename_fields(env) diff --git a/l10n_it_asset_management/models/account_fiscal_year.py b/l10n_it_asset_management/models/account_fiscal_year.py index 64d697d50dce..45dd33822e28 100644 --- a/l10n_it_asset_management/models/account_fiscal_year.py +++ b/l10n_it_asset_management/models/account_fiscal_year.py @@ -35,3 +35,25 @@ def get_fiscal_year_by_date_domain(self, date, company=None): if company: domain.append(("company_id", "in", company.ids)) return domain + + @api.model + def _get_passed_years(self, start_date, end_date): + """Find all fiscal years between `start_date` and `end_date`.""" + if start_date and end_date: + overlapping_fiscal_year_domain = self.new( + { + "date_from": start_date, + "date_to": end_date, + } + )._get_overlapping_domain() + # Exclude current record's NewId + # because it is not supported in domains + overlapping_fiscal_year_domain = [ + term if term[0] != "id" else ("id", "!=", 0) + for term in overlapping_fiscal_year_domain + ] + overlapping_fiscal_years = self.search(overlapping_fiscal_year_domain) + passed_years = len(overlapping_fiscal_years) + else: + passed_years = None + return passed_years diff --git a/l10n_it_asset_management/models/asset_depreciation.py b/l10n_it_asset_management/models/asset_depreciation.py index 994d50671c25..78ef4ebbb9ed 100644 --- a/l10n_it_asset_management/models/asset_depreciation.py +++ b/l10n_it_asset_management/models/asset_depreciation.py @@ -139,6 +139,51 @@ class AssetDepreciation(models.Model): zero_depreciation_until = fields.Date(string="Zero Depreciation Up To") + depreciation_account_id = fields.Many2one( + comodel_name="account.account", + compute="_compute_depreciation_account_id", + readonly=False, + store=True, + string="Depreciation Account", + ) + gain_account_id = fields.Many2one( + comodel_name="account.account", + compute="_compute_gain_account_id", + readonly=False, + store=True, + string="Capital Gain Account", + ) + loss_account_id = fields.Many2one( + comodel_name="account.account", + compute="_compute_loss_account_id", + readonly=False, + store=True, + string="Capital Loss Account", + ) + + @api.depends( + "asset_id.category_id", + ) + def _compute_depreciation_account_id(self): + for dep in self: + dep.depreciation_account_id = ( + dep.asset_id.category_id.depreciation_account_id + ) + + @api.depends( + "asset_id.category_id", + ) + def _compute_gain_account_id(self): + for dep in self: + dep.gain_account_id = dep.asset_id.category_id.gain_account_id + + @api.depends( + "asset_id.category_id", + ) + def _compute_loss_account_id(self): + for dep in self: + dep.loss_account_id = dep.asset_id.category_id.loss_account_id + @api.model_create_multi def create(self, vals_list): depreciations = self.browse() @@ -289,26 +334,36 @@ def check_before_generate_depreciation_lines(self, dep_date): ) ) - def generate_depreciation_lines(self, dep_date): + def generate_depreciation_lines(self, dep_date, period=None, period_count=None): # Set new date within context if necessary self.check_before_generate_depreciation_lines(dep_date) new_lines = self.env["asset.depreciation.line"] for dep in self: - new_line = dep.generate_depreciation_lines_single(dep_date) + new_line = dep.generate_depreciation_lines_single( + dep_date, period=period, period_count=period_count + ) if new_line: new_lines |= new_line return new_lines - def generate_depreciation_lines_single(self, dep_date): + def generate_depreciation_lines_single( + self, dep_date, period=None, period_count=None + ): self.ensure_one() res = self.env["asset.depreciation.line"] if self.last_depreciation_date and self.last_depreciation_date > dep_date: return res - dep_nr = self.get_max_depreciation_nr() + 1 - dep = self.with_context(dep_nr=dep_nr, used_asset=self.asset_id.used) - dep_amount = dep.get_depreciation_amount(dep_date) + passed_fiscal_years = self.env["account.fiscal.year"]._get_passed_years( + self.asset_id.purchase_date, dep_date + ) + dep = self.with_context( + passed_fiscal_years=passed_fiscal_years, used_asset=self.asset_id.used + ) + dep_amount = dep.get_depreciation_amount( + dep_date, period=period, period_count=period_count + ) if not dep_amount: return res dep = dep.with_context(dep_amount=dep_amount) @@ -393,7 +448,7 @@ def get_depreciable_amount(self, dep_date=None): depreciable_amount = 0 return depreciable_amount - def get_depreciation_amount(self, dep_date): + def get_depreciation_amount(self, dep_date, period=None, period_count=None): self.ensure_one() zero_dep_date = self.zero_depreciation_until if zero_dep_date and dep_date <= zero_dep_date: @@ -401,7 +456,9 @@ def get_depreciation_amount(self, dep_date): # Get depreciable amount, multiplier and digits amount = self.get_depreciable_amount(dep_date) - multiplier = self.get_depreciation_amount_multiplier(dep_date) + multiplier = self.get_depreciation_amount_multiplier( + dep_date, period=period, period_count=period_count + ) digits = self.env["decimal.precision"].precision_get("Account") dep_amount = round(amount * multiplier, digits) @@ -411,12 +468,20 @@ def get_depreciation_amount(self, dep_date): return dep_amount - def get_depreciation_amount_multiplier(self, dep_date): + def get_depreciation_amount_multiplier( + self, dep_date, period=None, period_count=None + ): self.ensure_one() # Base multiplier multiplier = self.percentage / 100 + if period == "month": + multiplier /= 12 + + if period_count: + multiplier *= period_count + # Update multiplier from depreciation mode data multiplier *= self.mode_id.get_depreciation_amount_multiplier() @@ -503,14 +568,6 @@ def get_dismiss_account_move_vals(self): "move_type": "entry", } - def get_max_depreciation_nr(self): - self.ensure_one() - num_lines = self.line_ids.filtered("requires_depreciation_nr") - nums = num_lines.mapped("depreciation_nr") - if not nums: - nums = [0] - return max(nums) - def get_pro_rata_temporis_dates(self, date): """ Gets useful dates for pro rata temporis computations, according to diff --git a/l10n_it_asset_management/models/asset_depreciation_line.py b/l10n_it_asset_management/models/asset_depreciation_line.py index 40296df2b197..9f13c11eb15c 100644 --- a/l10n_it_asset_management/models/asset_depreciation_line.py +++ b/l10n_it_asset_management/models/asset_depreciation_line.py @@ -119,7 +119,7 @@ class AssetDepreciationLine(models.Model): _numbered_move_types = ("depreciated", "historical") # Non-default parameter: set which `move_types` do not concur to # asset.depreciation's `amount_residual` field compute - _non_residual_move_types = ("gain",) + _non_residual_move_types = ("gain", "loss") # Non-default parameter: set which `move_types` get to update the # depreciable amount _update_move_types = ("in", "out") @@ -362,10 +362,14 @@ def generate_account_move_single(self): def get_account_move_vals(self): self.ensure_one() + journal = self.env.context.get( + "l10n_it_asset_override_journal", + self.asset_id.category_id.journal_id, + ) return { "company_id": self.company_id.id, "date": self.date, - "journal_id": self.asset_id.category_id.journal_id.id, + "journal_id": journal.id, "line_ids": [], "ref": _("Asset: ") + self.asset_id.make_name(), "move_type": "entry", @@ -396,7 +400,7 @@ def get_depreciated_account_move_line_vals(self): # Asset depreciation if not self.partial_dismissal: credit_account_id = self.asset_id.category_id.fund_account_id.id - debit_account_id = self.asset_id.category_id.depreciation_account_id.id + debit_account_id = self.depreciation_id.depreciation_account_id.id # Asset partial dismissal else: @@ -423,7 +427,7 @@ def get_depreciated_account_move_line_vals(self): def get_gain_account_move_line_vals(self): self.ensure_one() credit_line_vals = { - "account_id": self.asset_id.category_id.gain_account_id.id, + "account_id": self.depreciation_id.gain_account_id.id, "credit": self.amount, "debit": 0.0, "currency_id": self.currency_id.id, @@ -458,7 +462,7 @@ def get_loss_account_move_line_vals(self): "name": " - ".join((self.asset_id.make_name(), self.name)), } debit_line_vals = { - "account_id": self.asset_id.category_id.loss_account_id.id, + "account_id": self.depreciation_id.loss_account_id.id, "credit": 0.0, "debit": self.amount, "currency_id": self.currency_id.id, diff --git a/l10n_it_asset_management/models/asset_depreciation_mode_line.py b/l10n_it_asset_management/models/asset_depreciation_mode_line.py index 55474f8c992d..541489c51ff1 100644 --- a/l10n_it_asset_management/models/asset_depreciation_mode_line.py +++ b/l10n_it_asset_management/models/asset_depreciation_mode_line.py @@ -9,7 +9,7 @@ class AssetDepreciationModeLine(models.Model): _name = "asset.depreciation.mode.line" _description = "Asset Depreciation Mode Line" - _order = "from_nr asc, to_nr asc" + _order = "from_year_nr asc, to_year_nr asc" application = fields.Selection( [("coefficient", "Coefficient"), ("percentage", "Percentage")], @@ -24,8 +24,12 @@ class AssetDepreciationModeLine(models.Model): "res.company", readonly=True, related="mode_id.company_id", string="Company" ) - from_nr = fields.Integer( + from_year_nr = fields.Integer( required=True, + string="From Year", + help="Minimum number of fiscal years passed " + "from asset purchase date " + "to apply this line.", ) mode_id = fields.Many2one( @@ -38,7 +42,12 @@ class AssetDepreciationModeLine(models.Model): percentage = fields.Float() - to_nr = fields.Integer() + to_year_nr = fields.Integer( + string="To Year", + help="Maximum number of fiscal years passed " + "from asset purchase date " + "to apply this line.", + ) @api.onchange("application") def onchange_application(self): @@ -53,13 +62,14 @@ def onchange_application(self): def get_depreciation_amount_multiplier(self): multiplier = 1 - nr = self._context.get("dep_nr") - if nr is None: + passed_fiscal_years = self._context.get("passed_fiscal_years") + if passed_fiscal_years is None: # Cannot compare to any line return multiplier lines = self.filtered( - lambda line: line.from_nr <= nr and (not line.to_nr or line.to_nr >= nr) + lambda line: line.from_year_nr <= passed_fiscal_years + and (not line.to_year_nr or line.to_year_nr >= passed_fiscal_years) ) if not lines: return multiplier diff --git a/l10n_it_asset_management/static/description/index.html b/l10n_it_asset_management/static/description/index.html index e8d20b8bfad4..bb6ce773a1f5 100644 --- a/l10n_it_asset_management/static/description/index.html +++ b/l10n_it_asset_management/static/description/index.html @@ -367,7 +367,7 @@

ITA - Gestione Cespiti

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:5c523a2684aa69e490e6fe09e1700c382ee33ce9c9d69c1d1a7b66d4a454ec23 +!! source digest: sha256:61b720888e8c18d6974ba493322d56acd2195125d900de1fc6c85f9069c7e5df !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

This modules allows account management of companies’ assets.

diff --git a/l10n_it_asset_management/tests/__init__.py b/l10n_it_asset_management/tests/__init__.py index 5ddb45a9e1ec..c026ba7a1319 100644 --- a/l10n_it_asset_management/tests/__init__.py +++ b/l10n_it_asset_management/tests/__init__.py @@ -1,3 +1,4 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import test_assets_management +from . import test_asset_depreciation diff --git a/l10n_it_asset_management/tests/common.py b/l10n_it_asset_management/tests/common.py new file mode 100644 index 000000000000..b307a145b18d --- /dev/null +++ b/l10n_it_asset_management/tests/common.py @@ -0,0 +1,396 @@ +# Copyright 2021 Sergio Corato +# Copyright 2022 Simone Rubino - TAKOBI +# Copyright 2023 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import date + +from odoo.fields import Command, first +from odoo.tests.common import Form, TransactionCase + + +class Common(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.data_account_type_current_assets = "asset_current" + + cls.asset_fixed_account = cls.env["account.account"].search( + [ + ( + "account_type", + "=", + "asset_fixed", + ) + ], + limit=1, + ) + cls.expense_account = cls.env["account.account"].search( + [ + ( + "account_type", + "=", + "expense", + ) + ], + limit=1, + ) + cls.asset_non_current_account = cls.env["account.account"].search( + [ + ( + "account_type", + "=", + "asset_non_current", + ) + ], + limit=1, + ) + cls.income_account = cls.env["account.account"].search( + [ + ( + "account_type", + "=", + "income", + ) + ], + limit=1, + ) + + cls.general_journal = cls.env["account.journal"].search( + [("type", "=", "general")], limit=1 + ) + cls.purchase_journal = cls.env["account.journal"].search( + [ + ("type", "=", "purchase"), + ], + limit=1, + ) + cls.sale_journal = cls.env["account.journal"].search( + [ + ("type", "=", "sale"), + ], + limit=1, + ) + + cls.civilistico_asset_dep_type = cls.env.ref( + "l10n_it_asset_management.ad_type_civilistico" + ) + + cls.materiale_asset_dep_mode = cls.env.ref( + "l10n_it_asset_management.ad_mode_materiale" + ) + + cls.asset_category_1 = cls.env["asset.category"].create( + { + "name": "Asset category 1", + "asset_account_id": cls.asset_fixed_account.id, + "depreciation_account_id": cls.expense_account.id, + "fund_account_id": cls.asset_non_current_account.id, + "gain_account_id": cls.income_account.id, + "journal_id": cls.general_journal.id, + "loss_account_id": cls.expense_account.id, + "type_ids": [ + Command.create( + { + "depreciation_type_id": cls.civilistico_asset_dep_type.id, + "mode_id": cls.materiale_asset_dep_mode.id, + }, + ) + ], + } + ) + cls.tax_account = cls.env["account.account"].create( + { + "name": "Deductable tax", + "code": "DEDTAX", + "account_type": cls.data_account_type_current_assets, + } + ) + cls.tax_22_partial_60 = cls.env["account.tax"].create( + { + "name": "22% deductable partial 60%", + "type_tax_use": "purchase", + "amount_type": "percent", + "amount": 22, + "invoice_repartition_line_ids": [ + Command.create( + { + "factor_percent": 100, + "repartition_type": "base", + }, + ), + Command.create( + { + "factor_percent": 60, + "repartition_type": "tax", + "account_id": cls.tax_account.id, + }, + ), + Command.create( + { + "factor_percent": 40, + "repartition_type": "tax", + }, + ), + ], + "refund_repartition_line_ids": [ + Command.create( + { + "factor_percent": 100, + "repartition_type": "base", + }, + ), + Command.create( + { + "factor_percent": 60, + "repartition_type": "tax", + "account_id": cls.tax_account.id, + }, + ), + Command.create( + { + "factor_percent": 40, + "repartition_type": "tax", + }, + ), + ], + } + ) + cls.bank_account = cls.env["account.account"].create( + { + "code": "TBA", + "name": "Test Bank Account", + "account_type": "asset_cash", + } + ) + cls.env.user.groups_id += cls.env.ref("account.group_account_readonly") + + def _create_asset(self, asset_date=None): + asset = self.env["asset.asset"].create( + { + "name": "Test asset", + "category_id": self.asset_category_1.id, + "company_id": self.env.ref("base.main_company").id, + "currency_id": self.env.ref("base.main_company").currency_id.id, + "purchase_amount": 1000.0, + "purchase_date": asset_date, + } + ) + return asset + + def _depreciate_asset_wizard( + self, + asset, + date_dep, + period="year", + period_count=None, + override_journal=None, + ): + if override_journal is None: + override_journal = self.env["account.journal"].browse() + wiz_vals = asset.with_context( + **{"allow_reload_window": True} + ).launch_wizard_generate_depreciations() + wiz = ( + self.env["wizard.asset.generate.depreciation"] + .with_context(**wiz_vals["context"]) + .create( + { + "date_dep": date_dep, + "period": period, + "period_count": period_count, + "journal_id": override_journal.id, + } + ) + ) + return wiz + + def _depreciate_asset( + self, + asset, + date_dep, + period="year", + period_count=None, + override_journal=None, + ): + wiz = self._depreciate_asset_wizard( + asset, + date_dep, + period=period, + period_count=period_count, + override_journal=override_journal, + ) + wiz.do_generate() + + def _create_purchase_invoice(self, invoice_date, tax_ids=False, amount=7000): + invoice_line_vals = { + "account_id": self.asset_category_1.asset_account_id.id, + "quantity": 1, + "price_unit": amount, + } + if tax_ids: + invoice_line_vals.update({"tax_ids": tax_ids}) + purchase_invoice = self.env["account.move"].create( + { + "move_type": "in_invoice", + "invoice_date": invoice_date, + "partner_id": self.env.ref("base.partner_demo").id, + "journal_id": self.env["account.journal"] + .search( + [ + ("type", "=", "purchase"), + ], + limit=1, + ) + .id, + "invoice_line_ids": [ + Command.create( + invoice_line_vals, + ) + ], + } + ) + purchase_invoice.action_post() + self.assertEqual(purchase_invoice.state, "posted") + return purchase_invoice + + def _create_sale_invoice(self, asset, amount=7000, invoice_date=None, post=True): + sale_invoice = self.env["account.move"].create( + { + "move_type": "out_invoice", + "invoice_date": invoice_date, + "partner_id": self.env.ref("base.partner_demo").id, + "journal_id": self.sale_journal.id, + "invoice_line_ids": [ + Command.create( + { + "account_id": asset.category_id.asset_account_id.id, + "quantity": 1, + "price_unit": amount, + }, + ) + ], + } + ) + if post: + sale_invoice.action_post() + return sale_invoice + + def _create_entry(self, account, amount, post=True): + """Create an entry that adds `amount` to `account`.""" + entry_form = Form(self.env["account.move"]) + with entry_form.line_ids.new() as asset_line: + asset_line.account_id = account + asset_line.debit = amount + with entry_form.line_ids.new() as bank_line: + bank_line.account_id = self.bank_account + entry = entry_form.save() + + if post: + entry.action_post() + + self.assertEqual(entry.move_type, "entry") + return entry + + def _civil_depreciate_asset(self, asset): + # Keep only one civil depreciation + civil_depreciation_type = self.env.ref( + "l10n_it_asset_management.ad_type_civilistico" + ) + civil_depreciation = first( + asset.depreciation_ids.filtered( + lambda d: d.type_id == civil_depreciation_type + ) + ) + (asset.depreciation_ids - civil_depreciation).unlink() + + civil_depreciation.line_ids = [ + Command.clear(), + Command.create( + { + "name": "2019", + "date": date(2019, 12, 31), + "move_type": "depreciated", + "amount": 500, + }, + ), + Command.create( + { + "name": "2020", + "date": date(2020, 12, 31), + "move_type": "depreciated", + "amount": 500, + }, + ), + ] + return True + + def _generate_fiscal_years(self, start_date, end_date): + fiscal_years = range( + start_date.year, + end_date.year + 1, + ) + fiscal_years_values = list() + for fiscal_year in fiscal_years: + fiscal_year_values = { + "name": "Fiscal Year %d" % fiscal_year, + "date_from": date(fiscal_year, 1, 1), + "date_to": date(fiscal_year, 12, 31), + } + fiscal_years_values.append(fiscal_year_values) + return self.env["account.fiscal.year"].create(fiscal_years_values) + + def _get_report_values(self, report_type): + if report_type == "previsional": + wizard_model = "wizard.asset.previsional.report" + report_model = "report_asset_previsional" + export_method = "export_asset_previsional_report" + elif report_type == "journal": + wizard_model = "wizard.asset.journal.report" + report_model = "report_asset_journal" + export_method = "export_asset_journal_report" + else: + raise Exception("Report can only be 'journal' or 'previsional'") + return export_method, report_model, wizard_model + + def _get_report(self, report_date, report_type): + export_method, report_model, wizard_model = self._get_report_values(report_type) + + wiz = self.env[wizard_model].create( + { + "date": report_date, + } + ) + report_result = getattr(wiz, export_method)() + report_ids = report_result["context"]["report_action"]["context"]["active_ids"] + report = self.env[report_model].browse(report_ids) + return report + + def _get_move_asset_wizard(self, move, link_management_type, wiz_values=None): + """Get the wizard that links `move` to an asset + with mode `link_management_type`. + `wiz_values` are values to be set in the wizard. + """ + if wiz_values is None: + wiz_values = {} + + wiz_action_values = move.open_wizard_manage_asset() + wiz_form = Form( + self.env["wizard.account.move.manage.asset"].with_context( + **wiz_action_values["context"] + ) + ) + wiz_form.management_type = link_management_type + for field_name, field_value in wiz_values.items(): + setattr(wiz_form, field_name, field_value) + wiz = wiz_form.save() + return wiz + + def _link_asset_move(self, move, link_management_type, wiz_values=None): + """Link `move` to an asset with mode `link_management_type`. + `wiz_values` are values to be set in the wizard. + """ + wiz = self._get_move_asset_wizard( + move, link_management_type, wiz_values=wiz_values + ) + return wiz.link_asset() diff --git a/l10n_it_asset_management/tests/test_asset_depreciation.py b/l10n_it_asset_management/tests/test_asset_depreciation.py new file mode 100644 index 000000000000..b3b355fc95db --- /dev/null +++ b/l10n_it_asset_management/tests/test_asset_depreciation.py @@ -0,0 +1,233 @@ +# Copyright 2024 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import date + +from .common import Common + + +class TestAssetDepreciation(Common): + def test_line_accounts(self): + """Accounts can be overridden in asset depreciation. + Overridden accounts are used in generated moves. + """ + new_depreciation_account = self.expense_account.copy() + + purchase_date = date(2020, month=1, day=1) + asset = self._create_asset(purchase_date) + + depreciation_date = date(2020, month=12, day=31) + asset_depreciation = asset.depreciation_ids.filtered( + lambda x, dev_type=self.civilistico_asset_dep_type: x.type_id == dev_type + ) + asset_depreciation.percentage = 20.0 + # pre-condition: depreciation accounts default to category accounts + self.assertEqual( + asset_depreciation.depreciation_account_id, + asset.category_id.depreciation_account_id, + ) + self.assertEqual( + asset_depreciation.gain_account_id, asset.category_id.gain_account_id + ) + self.assertEqual( + asset_depreciation.loss_account_id, asset.category_id.loss_account_id + ) + + # Act: change depreciation account and generate move + asset_depreciation.depreciation_account_id = new_depreciation_account + self._depreciate_asset(asset, depreciation_date) + + # Assert: new account is used in generated move + depreciation_move = asset_depreciation.line_ids.move_id + self.assertIn(new_depreciation_account, depreciation_move.line_ids.account_id) + + def test_depreciate_sale_loss_coefficient(self): + """Depreciate and sale an asset with a sale invoice. + Loss is proportional to the depreciation coefficient.""" + # Arrange + asset_dep_type = self.civilistico_asset_dep_type + asset_category = self.asset_category_1 + + purchase_date = date(2020, month=1, day=1) + depreciation_base_coeff = 0.2 + depreciation_percentage = 20.0 + depreciation_date = date(2020, month=12, day=31) + depreciated_amount = 160 + sale_price = 500 + + category_depreciation_type = asset_category.type_ids.filtered( + lambda x, dep_type=asset_dep_type: x.depreciation_type_id == dep_type + ) + category_depreciation_type.base_coeff = depreciation_base_coeff + category_depreciation_type.percentage = depreciation_percentage + category_depreciation_type.mode_id.line_ids.unlink() + + asset = self._create_asset(purchase_date) + self.assertEqual(asset.category_id, asset_category) + asset_depreciation = asset.depreciation_ids.filtered( + lambda x, dep_type=asset_dep_type: x.type_id == dep_type + ) + # pre-condition + self.assertEqual(asset_depreciation.base_coeff, depreciation_base_coeff) + self.assertEqual(asset_depreciation.percentage, depreciation_percentage) + self.assertEqual(asset_depreciation.amount_residual, 200) + + # Act: Depreciate and dismiss with sale + self._depreciate_asset(asset, depreciation_date) + self.assertEqual(asset_depreciation.amount_residual, depreciated_amount) + depreciation_lines = asset_depreciation.line_ids + sale_invoice = self._create_sale_invoice(asset, amount=sale_price) + self._link_asset_move( + sale_invoice, + "dismiss", + wiz_values={ + "asset_id": asset, + }, + ) + + # Assert: Loss is proportional to `depreciation_base_coeff` + depreciation_lines = asset_depreciation.line_ids - depreciation_lines + self.assertRecordValues( + depreciation_lines.sorted("move_type"), + [ + { + "move_type": "loss", + "amount": abs( + sale_price * depreciation_base_coeff - depreciated_amount + ), + }, + { + "move_type": "out", + "amount": sale_price * depreciation_base_coeff, + }, + ], + ) + + def test_depreciate_update_loss_coefficient(self): + """Depreciate and update an asset with a purchase invoice. + 'In' depreciation line is proportional to the depreciation coefficient.""" + # Arrange + asset_dep_type = self.civilistico_asset_dep_type + asset_category = self.asset_category_1 + + purchase_date = date(2020, month=1, day=1) + depreciation_base_coeff = 0.2 + depreciation_percentage = 20.0 + depreciation_date = date(2020, month=12, day=31) + depreciated_amount = 160 + update_date = date(2021, month=6, day=6) + update_price = 500 + + category_depreciation_type = asset_category.type_ids.filtered( + lambda x, dep_type=asset_dep_type: x.depreciation_type_id == dep_type + ) + category_depreciation_type.base_coeff = depreciation_base_coeff + category_depreciation_type.percentage = depreciation_percentage + category_depreciation_type.mode_id.line_ids.unlink() + + asset = self._create_asset(purchase_date) + self.assertEqual(asset.category_id, asset_category) + asset_depreciation = asset.depreciation_ids.filtered( + lambda x, dep_type=asset_dep_type: x.type_id == dep_type + ) + # pre-condition + self.assertEqual(asset_depreciation.base_coeff, depreciation_base_coeff) + self.assertEqual(asset_depreciation.percentage, depreciation_percentage) + self.assertEqual(asset_depreciation.amount_residual, 200) + + # Act: Depreciate and update with purchase + self._depreciate_asset(asset, depreciation_date) + self.assertEqual(asset_depreciation.amount_residual, depreciated_amount) + depreciation_lines = asset_depreciation.line_ids + purchase_invoice = self._create_purchase_invoice( + update_date, amount=update_price + ) + self._link_asset_move( + purchase_invoice, + "update", + wiz_values={ + "asset_id": asset, + }, + ) + + # Assert: 'In' is proportional to `depreciation_base_coeff` + depreciation_lines = asset_depreciation.line_ids - depreciation_lines + self.assertRecordValues( + depreciation_lines, + [ + { + "move_type": "in", + "amount": update_price * depreciation_base_coeff, + }, + ], + ) + + def test_depreciate_partial_sale_loss_coefficient(self): + """Depreciate and partial depreciate an asset with a sale invoice. + Loss is proportional to the depreciation coefficient.""" + # Arrange + asset_dep_type = self.civilistico_asset_dep_type + asset_category = self.asset_category_1 + + purchase_date = date(2020, month=1, day=1) + depreciation_base_coeff = 0.2 + depreciation_percentage = 20.0 + depreciation_date = date(2020, month=12, day=31) + depreciated_amount = 160 + sale_price = 500 + depreciated_fund_amount = 100 + asset_purchase_amount = 200 + + category_depreciation_type = asset_category.type_ids.filtered( + lambda x, dep_type=asset_dep_type: x.depreciation_type_id == dep_type + ) + category_depreciation_type.base_coeff = depreciation_base_coeff + category_depreciation_type.percentage = depreciation_percentage + category_depreciation_type.mode_id.line_ids.unlink() + + asset = self._create_asset(purchase_date) + self.assertEqual(asset.category_id, asset_category) + asset_depreciation = asset.depreciation_ids.filtered( + lambda x, dep_type=asset_dep_type: x.type_id == dep_type + ) + # pre-condition + self.assertEqual(asset_depreciation.base_coeff, depreciation_base_coeff) + self.assertEqual(asset_depreciation.percentage, depreciation_percentage) + self.assertEqual(asset_depreciation.amount_residual, 200) + + # Act: Depreciate and update with purchase + self._depreciate_asset(asset, depreciation_date) + self.assertEqual(asset_depreciation.amount_residual, depreciated_amount) + depreciation_lines = asset_depreciation.line_ids + sale_invoice = self._create_sale_invoice(asset, amount=sale_price) + self._link_asset_move( + sale_invoice, + "partial_dismiss", + wiz_values={ + "asset_id": asset, + "depreciated_fund_amount": depreciated_fund_amount, + "asset_purchase_amount": asset_purchase_amount, + }, + ) + + # Assert: Create lines are proportional to `depreciation_base_coeff` + depreciation_lines = asset_depreciation.line_ids - depreciation_lines + self.assertRecordValues( + depreciation_lines.sorted("move_type"), + [ + { + "move_type": "depreciated", + "amount": -1 * depreciated_fund_amount * depreciation_base_coeff, + }, + { + "move_type": "gain", + "amount": sale_price * depreciation_base_coeff + - (asset_purchase_amount - depreciated_fund_amount) + * depreciation_base_coeff, + }, + { + "move_type": "out", + "amount": asset_purchase_amount * depreciation_base_coeff, + }, + ], + ) diff --git a/l10n_it_asset_management/tests/test_assets_management.py b/l10n_it_asset_management/tests/test_assets_management.py index a9d880e606bc..41f80ac93cc9 100644 --- a/l10n_it_asset_management/tests/test_assets_management.py +++ b/l10n_it_asset_management/tests/test_assets_management.py @@ -6,255 +6,27 @@ from odoo import fields from odoo.exceptions import ValidationError -from odoo.fields import Command, first -from odoo.tests import Form -from odoo.tests.common import TransactionCase +from odoo.fields import Command from odoo.tools.date_utils import relativedelta +from .common import Common -class TestAssets(TransactionCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.data_account_type_current_assets = "asset_current" - cls.asset_category_1 = cls.env["asset.category"].create( - { - "name": "Asset category 1", - "asset_account_id": cls.env["account.account"] - .search( - [ - ( - "account_type", - "=", - "asset_fixed", - ) - ], - limit=1, - ) - .id, - "depreciation_account_id": cls.env["account.account"] - .search( - [ - ( - "account_type", - "=", - "expense", - ) - ], - limit=1, - ) - .id, - "fund_account_id": cls.env["account.account"] - .search( - [ - ( - "account_type", - "=", - "asset_non_current", - ) - ], - limit=1, - ) - .id, - "gain_account_id": cls.env["account.account"] - .search( - [ - ( - "account_type", - "=", - "income", - ) - ], - limit=1, - ) - .id, - "journal_id": cls.env["account.journal"] - .search([("type", "=", "general")], limit=1) - .id, - "loss_account_id": cls.env["account.account"] - .search( - [ - ( - "account_type", - "=", - "expense", - ) - ], - limit=1, - ) - .id, - "type_ids": [ - Command.create( - { - "depreciation_type_id": cls.env.ref( - "l10n_it_asset_management.ad_type_civilistico" - ).id, - "mode_id": cls.env.ref( - "l10n_it_asset_management.ad_mode_materiale" - ).id, - }, - ) - ], - } - ) - cls.tax_account = cls.env["account.account"].create( - { - "name": "Deductable tax", - "code": "DEDTAX", - "account_type": cls.data_account_type_current_assets, - } - ) - cls.tax_22_partial_60 = cls.env["account.tax"].create( - { - "name": "22% deductable partial 60%", - "type_tax_use": "purchase", - "amount_type": "percent", - "amount": 22, - "invoice_repartition_line_ids": [ - Command.create( - { - "factor_percent": 100, - "repartition_type": "base", - }, - ), - Command.create( - { - "factor_percent": 60, - "repartition_type": "tax", - "account_id": cls.tax_account.id, - }, - ), - Command.create( - { - "factor_percent": 40, - "repartition_type": "tax", - }, - ), - ], - "refund_repartition_line_ids": [ - Command.create( - { - "factor_percent": 100, - "repartition_type": "base", - }, - ), - Command.create( - { - "factor_percent": 60, - "repartition_type": "tax", - "account_id": cls.tax_account.id, - }, - ), - Command.create( - { - "factor_percent": 40, - "repartition_type": "tax", - }, - ), - ], - } - ) - cls.bank_account = cls.env["account.account"].create( - { - "code": "TBA", - "name": "Test Bank Account", - "account_type": "asset_cash", - } - ) - cls.env.user.groups_id += cls.env.ref("account.group_account_readonly") - - def _create_asset(self, asset_date=None): - asset = self.env["asset.asset"].create( - { - "name": "Test asset", - "category_id": self.asset_category_1.id, - "company_id": self.env.ref("base.main_company").id, - "currency_id": self.env.ref("base.main_company").currency_id.id, - "purchase_amount": 1000.0, - "purchase_date": asset_date, - } - ) - return asset - - def _depreciate_asset(self, asset, date_dep): - wiz_vals = asset.with_context( - **{"allow_reload_window": True} - ).launch_wizard_generate_depreciations() - wiz = ( - self.env["wizard.asset.generate.depreciation"] - .with_context(**wiz_vals["context"]) - .create({"date_dep": date_dep}) - ) - wiz.do_generate() - - def _create_purchase_invoice(self, invoice_date, tax_ids=False, amount=7000): - invoice_line_vals = { - "account_id": self.asset_category_1.asset_account_id.id, - "quantity": 1, - "price_unit": amount, - } - if tax_ids: - invoice_line_vals.update({"tax_ids": tax_ids}) - purchase_invoice = self.env["account.move"].create( - { - "move_type": "in_invoice", - "invoice_date": invoice_date, - "partner_id": self.env.ref("base.partner_demo").id, - "journal_id": self.env["account.journal"] - .search( - [ - ("type", "=", "purchase"), - ], - limit=1, - ) - .id, - "invoice_line_ids": [ - Command.create( - invoice_line_vals, - ) - ], - } - ) - purchase_invoice.action_post() - self.assertEqual(purchase_invoice.state, "posted") - return purchase_invoice - - def _create_entry(self, account, amount, post=True): - """Create an entry that adds `amount` to `account`.""" - entry_form = Form(self.env["account.move"]) - with entry_form.line_ids.new() as asset_line: - asset_line.account_id = account - asset_line.debit = amount - with entry_form.line_ids.new() as bank_line: - bank_line.account_id = self.bank_account - entry = entry_form.save() - - if post: - entry.action_post() - - self.assertEqual(entry.move_type, "entry") - return entry - - def _update_asset(self, entry, asset): - """Execute the wizard on `entry` to update `asset`.""" - wizard_action = entry.open_wizard_manage_asset() - wizard_model = self.env[wizard_action["res_model"]] - wizard_context = wizard_action["context"] - - wizard_form = Form(wizard_model.with_context(**wizard_context)) - wizard_form.management_type = "update" - wizard_form.asset_id = asset - wizard = wizard_form.save() - - return wizard.link_asset() +class TestAssets(Common): def test_00_create_asset_depreciate_and_sale(self): today = fields.Date.today() + asset = self._create_asset(today + relativedelta(years=-1)) first_depreciation_date = today.replace(month=12, day=31) + relativedelta( years=-1 ) second_depreciation_date = today.replace(month=12, day=31) - asset = self._create_asset(today + relativedelta(years=-1)) + self._generate_fiscal_years( + asset.purchase_date, + max( + first_depreciation_date, + second_depreciation_date, + ), + ) civ_type = self.env.ref("l10n_it_asset_management.ad_type_civilistico") depreciation_id = asset.depreciation_ids.filtered( lambda x: x.type_id == civ_type @@ -513,6 +285,24 @@ def test_03_asset_from_purchase_invoice_increment(self): third_depreciation_date = today.replace(month=12, day=31) + relativedelta( years=-3 ) + # create depreciation for year -2 or -1 should do nothing as asset is totally + # depreciated + fourth_depreciation_date = today.replace(month=12, day=31) + relativedelta( + years=-2 + ) + # create depreciation for current year should depreciate totally (as computed + # value 9000*40% = 3600 is greater than residual value) + current_year_depreciation_date = today.replace(month=12, day=31) + self._generate_fiscal_years( + asset.purchase_date, + max( + first_depreciation_date, + second_depreciation_date, + third_depreciation_date, + fourth_depreciation_date, + current_year_depreciation_date, + ), + ) civ_type = self.env.ref("l10n_it_asset_management.ad_type_civilistico") depreciation_id = asset.depreciation_ids.filtered( lambda x: x.type_id == civ_type @@ -559,16 +349,8 @@ def test_03_asset_from_purchase_invoice_increment(self): ) wiz.link_asset() self.assertAlmostEqual(depreciation_id.amount_depreciable_updated, 9000) - # create depreciation for year -2 or -1 should do nothing as asset is totally - # depreciated - fourth_depreciation_date = today.replace(month=12, day=31) + relativedelta( - years=-2 - ) self._depreciate_asset(asset, fourth_depreciation_date) self.assertAlmostEqual(sum(civ_dep_lines.mapped("amount")), 7000) - # create depreciation for current year should depreciate totally (as computed - # value 9000*40% = 3600 is greater than residual value) - current_year_depreciation_date = today.replace(month=12, day=31) self._depreciate_asset(asset, current_year_depreciation_date) dep_lines = asset.depreciation_ids.line_ids civ_dep_lines = dep_lines.filtered( @@ -612,6 +394,23 @@ def test_04_asset_partial_depreciate_from_purchase_invoice_increment(self): second_depreciation_date = today.replace(month=12, day=31) + relativedelta( years=-3 ) + # create depreciation for year -4 should do nothing as asset is already + # depreciated in a later date + third_depreciation_date = today.replace(month=12, day=31) + relativedelta( + years=-4 + ) + # create depreciation for current year should depreciate totally (as computed + # value 9000*40% = 3600 is greater than residual value) + current_year_depreciation_date = today.replace(month=12, day=31) + self._generate_fiscal_years( + asset.purchase_date, + max( + first_depreciation_date, + second_depreciation_date, + third_depreciation_date, + current_year_depreciation_date, + ), + ) civ_type = self.env.ref("l10n_it_asset_management.ad_type_civilistico") depreciation_id = asset.depreciation_ids.filtered( lambda x: x.type_id == civ_type @@ -657,16 +456,8 @@ def test_04_asset_partial_depreciate_from_purchase_invoice_increment(self): ) wiz.link_asset() self.assertAlmostEqual(depreciation_id.amount_depreciable_updated, 9000) - # create depreciation for year -4 should do nothing as asset is already - # depreciated in a later date - third_depreciation_date = today.replace(month=12, day=31) + relativedelta( - years=-4 - ) self._depreciate_asset(asset, third_depreciation_date) self.assertAlmostEqual(sum(civ_dep_lines.mapped("amount")), 7000 * 0.6) - # create depreciation for current year should depreciate totally (as computed - # value 9000*40% = 3600 is greater than residual value) - current_year_depreciation_date = today.replace(month=12, day=31) self._depreciate_asset(asset, current_year_depreciation_date) dep_lines = asset.depreciation_ids.line_ids self.assertEqual(len(dep_lines), 4) @@ -690,7 +481,13 @@ def test_entry_in_update_asset(self): self.assertFalse(asset.asset_accounting_info_ids) # Act - self._update_asset(entry, asset) + self._link_asset_move( + entry, + "update", + wiz_values={ + "asset_id": asset, + }, + ) # Assert accounting_info = asset.asset_accounting_info_ids @@ -710,7 +507,13 @@ def test_entry_out_update_asset(self): self.assertFalse(asset.asset_accounting_info_ids) # Act - self._update_asset(entry, asset) + self._link_asset_move( + entry, + "update", + wiz_values={ + "asset_id": asset, + }, + ) # Assert accounting_info = asset.asset_accounting_info_ids @@ -720,80 +523,6 @@ def test_entry_out_update_asset(self): depreciation_info.amount_residual, asset.purchase_amount - removed_amount ) - def _civil_depreciate_asset(self, asset): - # Keep only one civil depreciation - civil_depreciation_type = self.env.ref( - "l10n_it_asset_management.ad_type_civilistico" - ) - civil_depreciation = first( - asset.depreciation_ids.filtered( - lambda d: d.type_id == civil_depreciation_type - ) - ) - (asset.depreciation_ids - civil_depreciation).unlink() - - civil_depreciation.line_ids = [ - Command.clear(), - Command.create( - { - "name": "2019", - "date": date(2019, 12, 31), - "move_type": "depreciated", - "amount": 500, - }, - ), - Command.create( - { - "name": "2020", - "date": date(2020, 12, 31), - "move_type": "depreciated", - "amount": 500, - }, - ), - ] - return True - - def _generate_fiscal_years(self, start_date, end_date): - fiscal_years = range( - start_date.year, - end_date.year, - ) - fiscal_years_values = list() - for fiscal_year in fiscal_years: - fiscal_year_values = { - "name": "Fiscal Year %d" % fiscal_year, - "date_from": date(fiscal_year, 1, 1), - "date_to": date(fiscal_year, 12, 31), - } - fiscal_years_values.append(fiscal_year_values) - return self.env["account.fiscal.year"].create(fiscal_years_values) - - def _get_report_values(self, report_type): - if report_type == "previsional": - wizard_model = "wizard.asset.previsional.report" - report_model = "report_asset_previsional" - export_method = "export_asset_previsional_report" - elif report_type == "journal": - wizard_model = "wizard.asset.journal.report" - report_model = "report_asset_journal" - export_method = "export_asset_journal_report" - else: - raise Exception("Report can only be 'journal' or 'previsional'") - return export_method, report_model, wizard_model - - def _get_report(self, report_date, report_type): - export_method, report_model, wizard_model = self._get_report_values(report_type) - - wiz = self.env[wizard_model].create( - { - "date": report_date, - } - ) - report_result = getattr(wiz, export_method)() - report_ids = report_result["context"]["report_action"]["context"]["active_ids"] - report = self.env[report_model].browse(report_ids) - return report - def test_journal_prev_year(self): """ Previous year depreciation considers depreciation of all previous years @@ -816,3 +545,189 @@ def test_journal_prev_year(self): total = report.report_total_ids self.assertEqual(total.amount_depreciation_fund_curr_year, 1000) self.assertEqual(total.amount_depreciation_fund_prev_year, 1000) + + def test_monthly_depreciation(self): + """ + Monthly depreciation uses 1/12 of the coefficient + of the year the depreciation is in. + """ + # Arrange + purchase_date = date(2019, 1, 1) + asset = self._create_asset(purchase_date) + first_depreciation_date = date(2019, 1, 31) + second_depreciation_date = date(2020, 1, 31) + third_depreciation_date = date(2021, 1, 31) + self._generate_fiscal_years( + asset.purchase_date, + max( + first_depreciation_date, + second_depreciation_date, + third_depreciation_date, + ), + ) + civ_depreciation_type = self.env.ref( + "l10n_it_asset_management.ad_type_civilistico" + ) + civ_depreciation = asset.depreciation_ids.filtered( + lambda x: x.type_id == civ_depreciation_type + ) + civ_depreciation.percentage = 12.0 + depreciation_mode = asset.category_id.type_ids.mode_id + # pre-condition + self.assertEqual(asset.purchase_date, purchase_date) + self.assertEqual(civ_depreciation.amount_depreciable, 1000) + self.assertRecordValues( + depreciation_mode.line_ids, + [ + { + "from_year_nr": 1, + "to_year_nr": 1, + "application": "coefficient", + "coefficient": 0.5, + }, + ], + ) + + # Act + self._depreciate_asset(asset, first_depreciation_date, period="month") + self._depreciate_asset(asset, second_depreciation_date, period="month") + self._depreciate_asset( + asset, third_depreciation_date, period="month", period_count=2 + ) + + # Assert + self.assertRecordValues( + civ_depreciation.line_ids, + [ + { + "date": first_depreciation_date, + "amount": 5, + }, + { + "date": second_depreciation_date, + "amount": 10, + }, + { + "date": third_depreciation_date, + "amount": 20, + }, + ], + ) + + def test_missing_fiscal_year_warning(self): + """ + If some years are not configured as fiscal years, + the wizard shows a warning. + """ + # Arrange + purchase_date = date(2019, 1, 1) + asset = self._create_asset(purchase_date) + depreciation_date = date(2020, 1, 1) + + # Act + depreciate_wizard = self._depreciate_asset_wizard(asset, depreciation_date) + + # Assert 1: some fiscal years are missing + self.assertTrue(depreciate_wizard.missing_fiscal_year_warning) + + # Act 2: Generate missing years + self._generate_fiscal_years( + asset.purchase_date, + depreciation_date, + ) + + # Assert 2: no fiscal years are missing + depreciate_wizard = self._depreciate_asset_wizard(asset, depreciation_date) + self.assertFalse(depreciate_wizard.missing_fiscal_year_warning) + + def test_override_journal(self): + """ + Set an "Override Journal" in the depreciation wizard, + the journal entries are created in the selected journal. + """ + # Arrange + override_journal = self.env["account.journal"].create( + { + "name": "Test override journal", + "code": "TOJ", + "type": "general", + } + ) + purchase_date = date(2019, 1, 1) + asset = self._create_asset(purchase_date) + depreciation_date = date(2019, 1, 31) + self._generate_fiscal_years( + asset.purchase_date, + depreciation_date, + ) + civ_depreciation_type = self.env.ref( + "l10n_it_asset_management.ad_type_civilistico" + ) + civ_depreciation = asset.depreciation_ids.filtered( + lambda x: x.type_id == civ_depreciation_type + ) + civ_depreciation.percentage = 12.0 + depreciate_asset_wizard = self._depreciate_asset_wizard( + asset, + depreciation_date, + period="month", + override_journal=override_journal, + ) + # pre-condition + self.assertNotEqual( + depreciate_asset_wizard.journal_id, asset.category_id.journal_id + ) + + # Act + depreciate_asset_wizard.do_generate() + + # Assert + account_move = asset.depreciation_ids.line_ids.move_id + self.assertEqual(account_move.journal_id, depreciate_asset_wizard.journal_id) + + def test_same_asset_report_residual_partial_depreciation(self): + """ + Partially depreciate an asset, + the residual value in the asset and in the report are the same. + """ + # Arrange + purchase_date = date(2019, 1, 1) + purchase_amount = 1000 + sale_date = date(2020, 6, 15) + sale_amount = 500 + partial_dismiss_purchase_amount = 600 + partial_dismiss_fund_amount = 0 + report_date = date(2021, 12, 31) + expected_residual_amount = 400 + + asset = self._create_asset(asset_date=purchase_date) + sale_invoice = self._create_sale_invoice( + asset, amount=sale_amount, invoice_date=sale_date + ) + self._link_asset_move( + sale_invoice, + "partial_dismiss", + wiz_values={ + "asset_id": asset, + "asset_purchase_amount": partial_dismiss_purchase_amount, + "depreciated_fund_amount": partial_dismiss_fund_amount, + }, + ) + # pre-condition + self.assertEqual(asset.purchase_amount, purchase_amount) + self.assertEqual( + asset.depreciation_ids.amount_residual, expected_residual_amount + ) + + # Act + self._generate_fiscal_years(purchase_date, report_date) + report = self._get_report(report_date, "journal") + + # Assert + asset_report = report.report_asset_ids.filtered(lambda ar: ar.asset_id == asset) + asset_report_depreciation_line = ( + asset_report.report_depreciation_ids.report_depreciation_year_line_ids + ) + self.assertEqual( + asset_report_depreciation_line.amount_residual, expected_residual_amount + ) diff --git a/l10n_it_asset_management/views/asset_depreciation.xml b/l10n_it_asset_management/views/asset_depreciation.xml index 3193b56bd33a..7f6f73bf097e 100644 --- a/l10n_it_asset_management/views/asset_depreciation.xml +++ b/l10n_it_asset_management/views/asset_depreciation.xml @@ -46,6 +46,18 @@ name="base_coeff" attrs="{'readonly': [('state', '!=', 'non_depreciated')]}" /> + + + - - + + 0 else -1 # Block updates if the amount to be written off is higher than # the residual amount diff --git a/l10n_it_asset_management/wizard/asset_generate_depreciation.py b/l10n_it_asset_management/wizard/asset_generate_depreciation.py index 10a0d54e2e2f..f4c545af0a24 100644 --- a/l10n_it_asset_management/wizard/asset_generate_depreciation.py +++ b/l10n_it_asset_management/wizard/asset_generate_depreciation.py @@ -3,8 +3,9 @@ # Copyright 2023 Simone Rubino - Aion Tech # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import api, fields, models +from odoo import _, api, fields, models from odoo.fields import Command +from odoo.tools import format_date class WizardAssetsGenerateDepreciations(models.TransientModel): @@ -57,6 +58,70 @@ def get_default_type_ids(self): string="Depreciation Types", ) + journal_id = fields.Many2one( + comodel_name="account.journal", + string="Override journal", + help="Create move entries in this journal " + "instead of the category's journal.", + ) + period = fields.Selection( + selection=[ + ("year", "Year"), + ("month", "Month"), + ], + default="year", + required=True, + ) + period_count = fields.Integer( + string="Number of periods", + default=1, + ) + missing_fiscal_year_warning = fields.Text( + compute="_compute_missing_fiscal_year_warning", + help="Message to warn the user that some fiscal years are missing.", + ) + + @api.depends( + "date_dep", + "asset_ids.purchase_date", + ) + def _compute_missing_fiscal_year_warning(self): + _get_passed_years = self.env["account.fiscal.year"]._get_passed_years + for generate_depreciation in self: + depreciation_date = generate_depreciation.date_dep + for asset in generate_depreciation.asset_ids: + asset_date = asset.purchase_date + passed_years = depreciation_date.year - asset_date.year + 1 + passed_fiscal_years = _get_passed_years(asset_date, depreciation_date) + if passed_years != passed_fiscal_years: + missing_fiscal_year_warning = _( + "Some years between %(asset_date)s and %(depreciation_date)s " + "have no configured fiscal year " + "and will not be counted for depreciation.\n" + "Please configure every fiscal year " + "that has to be counted for depreciation.", + asset_date=format_date(generate_depreciation.env, asset_date), + depreciation_date=format_date( + generate_depreciation.env, depreciation_date + ), + ) + break + else: + missing_fiscal_year_warning = False + generate_depreciation.missing_fiscal_year_warning = ( + missing_fiscal_year_warning + ) + + def _get_depreciation_context(self): + # Add depreciation date in context just in case + depreciation_context = dict( + dep_date=self.date_dep, + ) + override_journal = self.journal_id + if override_journal: + depreciation_context["l10n_it_asset_override_journal"] = self.journal_id + return depreciation_context + def do_generate(self): """ Launches the generation of new depreciation lines for the retrieved @@ -64,9 +129,11 @@ def do_generate(self): Reloads the current window if necessary. """ self.ensure_one() - # Add depreciation date in context just in case - deps = self.env["asset.depreciation"] - all_deps = self.with_context(dep_date=self.date_dep).get_depreciations() + self_with_depreciation_context = self.with_context( + **self._get_depreciation_context() + ) + deps = self_with_depreciation_context.env["asset.depreciation"] + all_deps = self_with_depreciation_context.get_depreciations() for dep in all_deps: if ( not dep.last_depreciation_date @@ -74,7 +141,11 @@ def do_generate(self): ): deps |= dep if deps: - dep_lines = deps.generate_depreciation_lines(self.date_dep) + dep_lines = deps.generate_depreciation_lines( + self.date_dep, + period=self.period, + period_count=self.period_count, + ) deps.post_generate_depreciation_lines(dep_lines) if self._context.get("reload_window"): return {"type": "ir.actions.client", "tag": "reload"} diff --git a/l10n_it_asset_management/wizard/asset_generate_depreciation_view.xml b/l10n_it_asset_management/wizard/asset_generate_depreciation_view.xml index ef57b32aed91..95a205dd415b 100644 --- a/l10n_it_asset_management/wizard/asset_generate_depreciation_view.xml +++ b/l10n_it_asset_management/wizard/asset_generate_depreciation_view.xml @@ -8,11 +8,37 @@
+ + ITA - Libro giornale - Reportlab !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:406c815cf9f5d7858e2354cdb28c41b751c27edacf1b580a4ca626ef2ea10a9a +!! source digest: sha256:91af559133071364b21113152d074c2e22096b825300936d3a24de75f65d2fe9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Italiano

diff --git a/l10n_it_central_journal_reportlab/wizard/print_giornale.py b/l10n_it_central_journal_reportlab/wizard/print_giornale.py index 1dd40927d77a..5ea9a4e02e26 100644 --- a/l10n_it_central_journal_reportlab/wizard/print_giornale.py +++ b/l10n_it_central_journal_reportlab/wizard/print_giornale.py @@ -5,6 +5,7 @@ import base64 import io from datetime import timedelta +from xml.sax.saxutils import escape from reportlab.lib import colors from reportlab.lib.enums import TA_RIGHT @@ -322,8 +323,12 @@ def get_initial_balance_data_report_giornale(self): "", "", Paragraph(_("Initial Balance"), style_name), - Paragraph(formatLang(self.env, self.progressive_debit2), style_number), - Paragraph(formatLang(self.env, self.progressive_credit), style_number), + Paragraph( + escape(formatLang(self.env, self.progressive_debit2)), style_number + ), + Paragraph( + escape(formatLang(self.env, self.progressive_credit)), style_number + ), ] ] return initial_balance_data @@ -352,9 +357,6 @@ def get_grupped_final_tables_report_giornale( ) if not account_name: continue - # evitiamo che i caratteri < o > vengano interpretato come tag html - # dalla libreria reportlab - account_name = account_name.replace("<", "<").replace(">", ">") start_row += 1 row = Paragraph(str(start_row), style_name) @@ -391,15 +393,19 @@ def get_grupped_final_tables_report_giornale( # che un conto ha sia debito che credito lines_data = [] if line["debit"] > 0: - debit = Paragraph(formatLang(self.env, line["debit"]), style_number) - credit = Paragraph(formatLang(self.env, 0), style_number) + debit = Paragraph( + escape(formatLang(self.env, line["debit"])), style_number + ) + credit = Paragraph(escape(formatLang(self.env, 0)), style_number) list_balance.append((line["debit"], 0)) lines_data.append( [[row, date, ref, move, account, name, debit, credit]] ) if line["credit"] > 0: - debit = Paragraph(formatLang(self.env, 0), style_number) - credit = Paragraph(formatLang(self.env, line["credit"]), style_number) + debit = Paragraph(escape(formatLang(self.env, 0)), style_number) + credit = Paragraph( + escape(formatLang(self.env, line["credit"])), style_number + ) list_balance.append((0, line["credit"])) lines_data.append( [[row, date, ref, move, account, name, debit, credit]] @@ -437,25 +443,24 @@ def get_final_tables_report_giornale( for line in self.env["account.move.line"].browse(move_line_ids): start_row += 1 - row = Paragraph(str(start_row), style_name) - date = Paragraph(format_date(self.env, line.date), style_name) - ref = Paragraph(str(line.ref or ""), style_name) + row = Paragraph(escape(str(start_row)), style_name) + date = Paragraph(escape(format_date(self.env, line.date)), style_name) + ref = Paragraph(escape(str(line.ref or "")), style_name) move_name = line.move_id.name or "" - move = Paragraph(move_name, style_name) + move = Paragraph(escape(move_name), style_name) account_name = self._get_account_name_reportlab(line) # evitiamo che i caratteri < o > vengano interpretato come tag html # dalla libreria reportlab - account_name = account_name.replace("<", "<").replace(">", ">") - account = Paragraph(account_name, style_name) + account = Paragraph(escape(account_name), style_name) if line.account_id.account_type in [ "asset_receivable", "liability_payable", ]: - name = Paragraph(str(line.partner_id.name or ""), style_name) + name = Paragraph(escape(str(line.partner_id.name or "")), style_name) else: - name = Paragraph(str(line.name or ""), style_name) - debit = Paragraph(formatLang(self.env, line.debit), style_number) - credit = Paragraph(formatLang(self.env, line.credit), style_number) + name = Paragraph(escape(str(line.name or "")), style_name) + debit = Paragraph(escape(formatLang(self.env, line.debit)), style_number) + credit = Paragraph(escape(formatLang(self.env, line.credit)), style_number) list_balance.append((line.debit, line.credit)) line_data = [[row, date, ref, move, account, name, debit, credit]] if previous_move_name != move_name: @@ -484,8 +489,8 @@ def get_balance_data_report_giornale(self, tot_debit, tot_credit, final=False): "", "", name, - Paragraph(formatLang(self.env, tot_debit), style_number), - Paragraph(formatLang(self.env, tot_credit), style_number), + Paragraph(escape(formatLang(self.env, tot_debit)), style_number), + Paragraph(escape(formatLang(self.env, tot_credit)), style_number), ] ] return balance_data diff --git a/l10n_it_fatturapa_import_zip/README.rst b/l10n_it_fatturapa_import_zip/README.rst index f16e229f18d7..d3b0b5df333c 100644 --- a/l10n_it_fatturapa_import_zip/README.rst +++ b/l10n_it_fatturapa_import_zip/README.rst @@ -7,7 +7,7 @@ ITA - Fattura elettronica - Import ZIP !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:43950c38a68623c63760ac2a42ad9a8142b0fbe4e9ff180eb002c6d3d8b9add0 + !! source digest: sha256:041abbe376467b79e97306464018cb953d95405e6adce9dbcb7faaeda483498c !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/l10n_it_fatturapa_import_zip/__manifest__.py b/l10n_it_fatturapa_import_zip/__manifest__.py index 9792dd499d55..59b010f8721f 100644 --- a/l10n_it_fatturapa_import_zip/__manifest__.py +++ b/l10n_it_fatturapa_import_zip/__manifest__.py @@ -6,7 +6,7 @@ "name": "ITA - Fattura elettronica - Import ZIP", "summary": "Permette di importare in uno ZIP diversi file XML di " "fatture elettroniche", - "version": "16.0.1.2.0", + "version": "16.0.1.3.0", "category": "Localization/Italy", "website": "https://github.com/OCA/l10n-italy", "author": "TAKOBI, Odoo Community Association (OCA)", diff --git a/l10n_it_fatturapa_import_zip/i18n/it.po b/l10n_it_fatturapa_import_zip/i18n/it.po index e4295415622c..60d4205386d8 100644 --- a/l10n_it_fatturapa_import_zip/i18n/it.po +++ b/l10n_it_fatturapa_import_zip/i18n/it.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-11-19 16:10+0000\n" -"PO-Revision-Date: 2024-09-17 10:06+0000\n" +"PO-Revision-Date: 2024-10-21 10:06+0000\n" "Last-Translator: mymage \n" "Language-Team: \n" "Language: it\n" @@ -252,6 +252,16 @@ msgstr "Importa e-fattura" msgid "Import E-bill ZIP Files" msgstr "Importa file ZIP e-fattura" +#. module: l10n_it_fatturapa_import_zip +#: model:ir.actions.act_window,name:l10n_it_fatturapa_import_zip.action_wizard_import_fatturapa_out +msgid "Import Electronic Invoice Out" +msgstr "Importa fattura elettronica emessa" + +#. module: l10n_it_fatturapa_import_zip +#: model_terms:ir.ui.view,arch_db:l10n_it_fatturapa_import_zip.fatturapa_attachment_import_zip_form +msgid "Import Files (No Invoices)" +msgstr "Importa file (non fatture)" + #. module: l10n_it_fatturapa_import_zip #: model_terms:ir.ui.view,arch_db:l10n_it_fatturapa_import_zip.fatturapa_attachment_import_zip_form msgid "Import e-bill ZIP" @@ -403,6 +413,17 @@ msgstr "Allegato originale (non ottimizzato, non ridimensionato)" msgid "Out invoices" msgstr "Fatture emesse" +#. module: l10n_it_fatturapa_import_zip +#. odoo-python +#: code:addons/l10n_it_fatturapa_import_zip/wizards/wizard_import_fatturapa.py:0 +#, python-format +msgid "" +"Please configure Default Debit Account in Journal '{journal}' or check " +"default income account for company '{company}'." +msgstr "" +"Configurare il conto debito predefinito nel registro '{journal}' o " +"controllare il conto ricavi predefinito per l'azienda '{company}'." + #. module: l10n_it_fatturapa_import_zip #: model:ir.model.fields,field_description:l10n_it_fatturapa_import_zip.field_fatturapa_attachment_import_zip__res_field msgid "Resource Field" diff --git a/l10n_it_fatturapa_import_zip/i18n/l10n_it_fatturapa_import_zip.pot b/l10n_it_fatturapa_import_zip/i18n/l10n_it_fatturapa_import_zip.pot index c3616bc4536c..f9123f6d7eb8 100644 --- a/l10n_it_fatturapa_import_zip/i18n/l10n_it_fatturapa_import_zip.pot +++ b/l10n_it_fatturapa_import_zip/i18n/l10n_it_fatturapa_import_zip.pot @@ -246,6 +246,16 @@ msgstr "" msgid "Import E-bill ZIP Files" msgstr "" +#. module: l10n_it_fatturapa_import_zip +#: model:ir.actions.act_window,name:l10n_it_fatturapa_import_zip.action_wizard_import_fatturapa_out +msgid "Import Electronic Invoice Out" +msgstr "" + +#. module: l10n_it_fatturapa_import_zip +#: model_terms:ir.ui.view,arch_db:l10n_it_fatturapa_import_zip.fatturapa_attachment_import_zip_form +msgid "Import Files (No Invoices)" +msgstr "" + #. module: l10n_it_fatturapa_import_zip #: model_terms:ir.ui.view,arch_db:l10n_it_fatturapa_import_zip.fatturapa_attachment_import_zip_form msgid "Import e-bill ZIP" @@ -397,6 +407,15 @@ msgstr "" msgid "Out invoices" msgstr "" +#. module: l10n_it_fatturapa_import_zip +#. odoo-python +#: code:addons/l10n_it_fatturapa_import_zip/wizards/wizard_import_fatturapa.py:0 +#, python-format +msgid "" +"Please configure Default Debit Account in Journal '{journal}' or check " +"default income account for company '{company}'." +msgstr "" + #. module: l10n_it_fatturapa_import_zip #: model:ir.model.fields,field_description:l10n_it_fatturapa_import_zip.field_fatturapa_attachment_import_zip__res_field msgid "Resource Field" diff --git a/l10n_it_fatturapa_import_zip/models/attachment.py b/l10n_it_fatturapa_import_zip/models/attachment.py index 4ecc28574cd9..cc0ea235582d 100644 --- a/l10n_it_fatturapa_import_zip/models/attachment.py +++ b/l10n_it_fatturapa_import_zip/models/attachment.py @@ -152,7 +152,7 @@ def _compute_invoices_data(self): ), ) - def action_import(self): + def action_import(self, with_invoice=True): self.ensure_one() company_partner = self.env.company.partner_id with tempfile.TemporaryDirectory() as tmp_dir_path: @@ -182,16 +182,17 @@ def action_import(self): attachment = self.env["fatturapa.attachment.out"].create( attach_vals ) - wizard = ( - self.env["wizard.import.fatturapa"] - .with_context( - active_ids=attachment.ids, - active_model=attachment._name, + if with_invoice: + wizard = ( + self.env["wizard.import.fatturapa"] + .with_context( + active_ids=attachment.ids, + active_model=attachment._name, + ) + .create({}) ) - .create({}) - ) - _logger.info(f"Importing {xml_file}") - wizard.importFatturaPA() + _logger.info(f"Importing {xml_file}") + wizard.importFatturaPA() else: _logger.info(f"Skipping {xml_file}, not an XML/P7M file") self.env.company.in_invoice_registration_date = ( @@ -200,6 +201,14 @@ def action_import(self): self.state = "done" + def action_import_with_invoice(self): + self.ensure_one() + self.action_import(with_invoice=True) + + def action_import_no_invoice(self): + self.ensure_one() + self.action_import(with_invoice=False) + class FatturaPAAttachmentIn(models.Model): _inherit = "fatturapa.attachment.in" diff --git a/l10n_it_fatturapa_import_zip/static/description/index.html b/l10n_it_fatturapa_import_zip/static/description/index.html index 489f2188e467..5a8349f2defa 100644 --- a/l10n_it_fatturapa_import_zip/static/description/index.html +++ b/l10n_it_fatturapa_import_zip/static/description/index.html @@ -367,7 +367,7 @@

ITA - Fattura elettronica - Import ZIP

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:43950c38a68623c63760ac2a42ad9a8142b0fbe4e9ff180eb002c6d3d8b9add0 +!! source digest: sha256:041abbe376467b79e97306464018cb953d95405e6adce9dbcb7faaeda483498c !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Italiano

diff --git a/l10n_it_fatturapa_import_zip/views/attachment_views.xml b/l10n_it_fatturapa_import_zip/views/attachment_views.xml index a811872a81ec..142a15aed7b8 100644 --- a/l10n_it_fatturapa_import_zip/views/attachment_views.xml +++ b/l10n_it_fatturapa_import_zip/views/attachment_views.xml @@ -7,13 +7,20 @@
-
@@ -173,4 +180,19 @@
+ + Import Electronic Invoice Out + wizard.import.fatturapa + + form + new + + + diff --git a/l10n_it_fatturapa_import_zip/wizards/wizard_import_fatturapa.py b/l10n_it_fatturapa_import_zip/wizards/wizard_import_fatturapa.py index 2b9c3a352c0c..41c5e3bd4aed 100644 --- a/l10n_it_fatturapa_import_zip/wizards/wizard_import_fatturapa.py +++ b/l10n_it_fatturapa_import_zip/wizards/wizard_import_fatturapa.py @@ -114,3 +114,57 @@ def set_payments_data(self, FatturaBody, invoice, partner_id): ) else: return super().set_payments_data(FatturaBody, invoice, partner_id) + + def _get_payment_term(self, partner): + payment_term_id = False + if self._is_import_attachment_out(): + if partner.property_payment_term_id: + payment_term_id = partner.property_payment_term_id.id + else: + payment_term_id = super()._get_payment_term(partner=partner) + return payment_term_id + + def get_credit_account(self, product=None): + if self._is_import_attachment_out(): + ret = self.get_debit_account(product=product) + else: + ret = super().get_credit_account(product=product) + return ret + + # function to mimics get_credit_account() for outgoing invoices + def get_debit_account(self, product=None): + debit_account = self.env["account.account"] + + if product: + template = product.product_tmpl_id + accounts_dict = template.get_product_accounts() + debit_account = accounts_dict["income"] + + company = self.env.company + # Search in journal + journal = self.get_journal(company) + if not debit_account: + debit_account = journal.default_account_id + + # Search in company defaults + if not debit_account: + debit_account = ( + self.env["ir.property"] + .with_company(company) + ._get("property_account_income_categ_id", "product.category") + ) + + if not debit_account: + raise UserError( + _( + "Please configure Default Debit Account " + "in Journal '{journal}' " + "or check default income account " + "for company '{company}'." + ).format( + journal=journal.display_name, + company=company.display_name, + ) + ) + + return debit_account diff --git a/l10n_it_fatturapa_in/README.rst b/l10n_it_fatturapa_in/README.rst index f1d247c1ef8d..cf3fd5b75478 100644 --- a/l10n_it_fatturapa_in/README.rst +++ b/l10n_it_fatturapa_in/README.rst @@ -7,7 +7,7 @@ ITA - Fattura elettronica - Ricezione !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:3d7a12d93c9e97e8328285e5480b0e6d917534591b34fa109c9742a6f8690b22 + !! source digest: sha256:a26eec486e0b51c07deb148e7bb2cb7d46112be4a72c77600c89bc4c63c88bc2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/l10n_it_fatturapa_in/__manifest__.py b/l10n_it_fatturapa_in/__manifest__.py index a2d9da41fbe3..7ffe26ae00d7 100644 --- a/l10n_it_fatturapa_in/__manifest__.py +++ b/l10n_it_fatturapa_in/__manifest__.py @@ -8,7 +8,7 @@ { "name": "ITA - Fattura elettronica - Ricezione", - "version": "16.0.1.3.0", + "version": "16.0.1.4.0", "development_status": "Beta", "category": "Localization/Italy", "summary": "Ricezione fatture elettroniche", diff --git a/l10n_it_fatturapa_in/i18n/it.po b/l10n_it_fatturapa_in/i18n/it.po index 7857fd0235cb..d050e6d86b29 100644 --- a/l10n_it_fatturapa_in/i18n/it.po +++ b/l10n_it_fatturapa_in/i18n/it.po @@ -153,17 +153,6 @@ msgstr "" "Totale imponibile: {bill_no_tax}\n" "Totale imposte: {bill_tax}" -#. module: l10n_it_fatturapa_in -#. odoo-python -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:0 -#, python-format -msgid "" -"Bill total %(amount_total)s is different from document total amount " -"%(document_total_amount)s" -msgstr "" -"Il totale fattura %(amount_total)s è diverso dall'importo totale del " -"documento %(document_total_amount)s" - #. module: l10n_it_fatturapa_in #: model_terms:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form msgid "Bills" @@ -665,13 +654,6 @@ msgstr "Forza validazione e-fattura" msgid "General Data" msgstr "Dati generali" -#. module: l10n_it_fatturapa_in -#. odoo-python -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:0 -#, python-format -msgid "Global bill discount from document general data" -msgstr "Sconto globale fattura dai dati generali del documento" - #. module: l10n_it_fatturapa_in #: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in__has_message msgid "Has Message" @@ -1649,6 +1631,18 @@ msgstr "" msgid "You can select only one XML file to link." msgstr "È possibile selezionare solo un file XML da collegare." +#, python-format +#~ msgid "" +#~ "Bill total %(amount_total)s is different from document total amount " +#~ "%(document_total_amount)s" +#~ msgstr "" +#~ "Il totale fattura %(amount_total)s è diverso dall'importo totale del " +#~ "documento %(document_total_amount)s" + +#, python-format +#~ msgid "Global bill discount from document general data" +#~ msgstr "Sconto globale fattura dai dati generali del documento" + #~ msgid "Creation" #~ msgstr "Creazione" diff --git a/l10n_it_fatturapa_in/i18n/l10n_it_fatturapa_in.pot b/l10n_it_fatturapa_in/i18n/l10n_it_fatturapa_in.pot index bb09c6fc29ed..5ec2accca275 100644 --- a/l10n_it_fatturapa_in/i18n/l10n_it_fatturapa_in.pot +++ b/l10n_it_fatturapa_in/i18n/l10n_it_fatturapa_in.pot @@ -132,15 +132,6 @@ msgid "" "Total tax: {bill_tax}" msgstr "" -#. module: l10n_it_fatturapa_in -#. odoo-python -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:0 -#, python-format -msgid "" -"Bill total %(amount_total)s is different from document total amount " -"%(document_total_amount)s" -msgstr "" - #. module: l10n_it_fatturapa_in #: model_terms:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form msgid "Bills" @@ -610,13 +601,6 @@ msgstr "" msgid "General Data" msgstr "" -#. module: l10n_it_fatturapa_in -#. odoo-python -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:0 -#, python-format -msgid "Global bill discount from document general data" -msgstr "" - #. module: l10n_it_fatturapa_in #: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in__has_message msgid "Has Message" diff --git a/l10n_it_fatturapa_in/models/attachment.py b/l10n_it_fatturapa_in/models/attachment.py index b5167a4f1c80..b096ec85bdf7 100644 --- a/l10n_it_fatturapa_in/models/attachment.py +++ b/l10n_it_fatturapa_in/models/attachment.py @@ -156,6 +156,7 @@ def _compute_e_invoice_parsing_error(self): @api.depends("ir_attachment_id.datas") def _compute_xml_data(self): + invoice_model = self.env["account.move"] for att in self: att.xml_supplier_id = False att.invoices_number = False @@ -170,11 +171,14 @@ def _compute_xml_data(self): # Look into each invoice to compute the following values invoices_date = [] for invoice_body in fatt.FatturaElettronicaBody: - # Assign this directly so that rounding is applied each time - att.invoices_total += float( - invoice_body.DatiGenerali.DatiGeneraliDocumento.ImportoTotaleDocumento - or 0 + amount_untaxed = invoice_model.compute_xml_amount_untaxed(invoice_body) + amount_tax = invoice_model.compute_xml_amount_tax( + invoice_body.DatiBeniServizi.DatiRiepilogo ) + amount_total = invoice_model.compute_xml_amount_total( + invoice_body, amount_untaxed, amount_tax + ) + att.invoices_total += amount_total document_date = invoice_body.DatiGenerali.DatiGeneraliDocumento.Data invoice_date = format_date( diff --git a/l10n_it_fatturapa_in/static/description/index.html b/l10n_it_fatturapa_in/static/description/index.html index d28068f8c794..922b8e1e9062 100644 --- a/l10n_it_fatturapa_in/static/description/index.html +++ b/l10n_it_fatturapa_in/static/description/index.html @@ -367,7 +367,7 @@

ITA - Fattura elettronica - Ricezione

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:3d7a12d93c9e97e8328285e5480b0e6d917534591b34fa109c9742a6f8690b22 +!! source digest: sha256:a26eec486e0b51c07deb148e7bb2cb7d46112be4a72c77600c89bc4c63c88bc2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Italiano

diff --git a/l10n_it_fatturapa_in/tests/data/IT08973230967_6zZcm.xml b/l10n_it_fatturapa_in/tests/data/IT08973230967_6zZcm.xml new file mode 100644 index 000000000000..f39a26112d97 --- /dev/null +++ b/l10n_it_fatturapa_in/tests/data/IT08973230967_6zZcm.xml @@ -0,0 +1,118 @@ + + + IT089732309676zZcmFPR12USAL8PV + + + + IT + 02581610249 + + + GAV spa + + RF01 + + + Via Meucci 11/15 + 36040 + Brendola + IT + + + + + + IT + 02780790107 + + + SOCIETA' ALPHA SRL + + + + VIALE ROMA 543 + 07100 + SASSARI + SS + IT + + + + + + IT + 00161809991 + + + Amazon Services Europe S.à r.l. + + + + TZ + + + + + TD01 + EUR + 2023-08-07 + IT23-94115I-790 + + SC + 1.23 + + 28.40 + 0.00 + + + 1 + 2 + 406-1634151-9421169 + 2023-08-06 + + + IT23-94115I-790 + 2023-08-07 + + + + + 1 + GAV Pistola Gonfiaggio Pneumatici Professionale Made in Italy con Manometro Pressione WIKA da 63mm per Pressione Gomme di Auto Moto Camion e Biciclette - Scala in BAR Psi - 60D (Standard) + 1.00 + 2023-08-07 + 2023-08-07 + 24.51 + + SC + 1.23 + + 23.28 + 22.00 + + + 2 + Costi di spedizione + 1.00 + 2023-08-07 + 2023-08-07 + 0.00 + 0.00 + 22.00 + + + 22.00 + -0.01 + 23.27 + 5.12 + + + + TP02 + + MP08 + 28.40 + + + + diff --git a/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py b/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py index bc67dd7708e0..be8f6ddc2ba7 100644 --- a/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py +++ b/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py @@ -200,18 +200,6 @@ def test_07_xml_import(self): self.assertEqual(invoice.e_invoice_validation_error, False) self.assertEqual(invoice.invoice_line_ids[0].admin_ref, "D122353") - def test_08_xml_import(self): - # using ImportoTotaleDocumento - res = self.run_wizard("test8", "IT05979361218_005.xml") - invoice_id = res.get("domain")[0][2][0] - invoice = self.invoice_model.browse(invoice_id) - self.assertEqual(invoice.ref, "FT/2015/0010") - self.assertEqual(invoice.payment_reference, "FT/2015/0010") - self.assertAlmostEqual(invoice.amount_total, 1288.61) - self.assertFalse(invoice.inconsistencies) - # allow following test to reuse the same XML file - invoice.ref = invoice.payment_reference = "14081" - def test_08_xml_import_no_account(self): """Check that a useful error message is raised when the credit account is missing in journal.""" @@ -236,21 +224,11 @@ def test_08_xml_import_no_account(self): self.assertIn(journal.display_name, ue.exception.args[0]) self.assertIn(company.display_name, ue.exception.args[0]) - discount_amount = -143.18 - # Restore the property and import the invoice expense_default_property.res_id = False res = self.run_wizard("test8_with_property", "IT05979361218_005.xml") invoice_id = res.get("domain")[0][2][0] invoice = self.invoice_model.browse(invoice_id) - invoice_lines = invoice.invoice_line_ids - discount_line = invoice_lines.filtered( - lambda line: line.price_unit == discount_amount - ) - self.assertEqual( - discount_line.account_id, - expense_default_property.get_by_record(), - ) # allow following code to reuse the same XML file invoice.ref = invoice.payment_reference = "14083" @@ -259,33 +237,10 @@ def test_08_xml_import_no_account(self): res = self.run_wizard("test8_with_journal", "IT05979361218_005.xml") invoice_id = res.get("domain")[0][2][0] invoice = self.invoice_model.browse(invoice_id) - invoice_lines = invoice.invoice_line_ids - discount_line = invoice_lines.filtered( - lambda line: line.price_unit == discount_amount - ) - self.assertEqual( - discount_line.account_id, - journal_account, - ) self.assertTrue(invoice) # allow following tests to reuse the same XML file invoice.ref = invoice.payment_reference = "14084" - def test_09_xml_import(self): - # using DatiGeneraliDocumento.ScontoMaggiorazione without - # ImportoTotaleDocumento - # add test file name case sensitive - res = self.run_wizard("test9", "IT05979361218_006.XML") - invoice_id = res.get("domain")[0][2][0] - invoice = self.invoice_model.browse(invoice_id) - self.assertEqual(invoice.ref, "FT/2015/0011") - self.assertEqual(invoice.payment_reference, "FT/2015/0011") - self.assertAlmostEqual(invoice.amount_total, 1288.61) - self.assertEqual( - invoice.inconsistencies, - "Computed amount untaxed 1030.42 is different from" " summary data 1173.6", - ) - def test_10_xml_import(self): # Fix Date format res = self.run_wizard("test6", "IT05979361218_007.xml") @@ -1182,6 +1137,19 @@ def test_access_other_user_e_invoice_attachments(self): e_invoice = invoices.fatturapa_doc_attachments self.assertTrue(e_invoice.ir_attachment_id.read()) + def test_ignore_global_discount(self): + """The nodes + - DatiGeneraliDocumento/ScontoMaggiorazione + - DatiGeneraliDocumento/ImportoTotaleDocumento + are not considered for invoice validation/consistency. + """ + res = self.run_wizard("ignore_global_discount", "IT08973230967_6zZcm.xml") + invoice = self.invoice_model.search(res["domain"]) + self.assertFalse(invoice.inconsistencies) + self.assertEqual(invoice.amount_untaxed, 23.27) + self.assertEqual(invoice.amount_tax, 5.12) + self.assertEqual(invoice.amount_total, 28.39) + class TestFatturaPAEnasarco(FatturapaCommon): def setUp(self): diff --git a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py index 0dd7b279252d..9973b3bcac9a 100644 --- a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py +++ b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py @@ -1,4 +1,5 @@ # Copyright 2022 Simone Rubino - TAKOBI +# Copyright 2024 Simone Rubino - Aion Tech # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import logging @@ -817,48 +818,6 @@ def _computeDiscount(self, DettaglioLinea): discount = (1 - (line_unit / float(DettaglioLinea.PrezzoUnitario))) * 100.0 return discount - def _addGlobalDiscount(self, invoice_id, DatiGeneraliDocumento): - discount = 0.0 - if ( - DatiGeneraliDocumento.ScontoMaggiorazione - and self.e_invoice_detail_level == "2" - ): - invoice = self.env["account.move"].browse(invoice_id) - for DiscRise in DatiGeneraliDocumento.ScontoMaggiorazione: - if DiscRise.Percentuale: - amount = invoice.amount_total * (float(DiscRise.Percentuale) / 100) - if DiscRise.Tipo == "SC": - discount -= amount - elif DiscRise.Tipo == "MG": - discount += amount - elif DiscRise.Importo: - if DiscRise.Tipo == "SC": - discount -= float(DiscRise.Importo) - elif DiscRise.Tipo == "MG": - discount += float(DiscRise.Importo) - company = invoice.company_id - global_discount_product = company.sconto_maggiorazione_product_id - credit_account = self.get_credit_account( - product=global_discount_product, - ) - line_vals = { - "move_id": invoice_id, - "name": _("Global bill discount from document general data"), - "account_id": credit_account.id, - "price_unit": discount, - "quantity": 1, - } - if global_discount_product: - line_vals["product_id"] = global_discount_product.id - line_vals["name"] = global_discount_product.name - self.adjust_accounting_data(global_discount_product, line_vals) - else: - line_vals["tax_ids"] = [fields.Command.clear()] - self.env["account.move.line"].with_context( - check_move_validity=False - ).create(line_vals) - return True - def _createPaymentsLine(self, payment_id, line, partner_id, invoice): details = line.DettaglioPagamento or False if details: @@ -1167,6 +1126,12 @@ def _get_received_date(self, attachment): received_date = received_date.date() return received_date + def _get_payment_term(self, partner): + payment_term_id = False + if partner.property_supplier_payment_term_id: + payment_term_id = partner.property_supplier_payment_term_id.id + return payment_term_id + def _prepare_invoice_values(self, fatt, fatturapa_attachment, FatturaBody, partner): company = self.env.company currency = self._get_currency(FatturaBody) @@ -1197,6 +1162,7 @@ def _prepare_invoice_values(self, fatt, fatturapa_attachment, FatturaBody, partn partner, delivery=delivery_partner, ) + payment_term_id = self._get_payment_term(partner) invoice_data = { "e_invoice_received_date": e_invoice_received_date, @@ -1212,7 +1178,7 @@ def _prepare_invoice_values(self, fatt, fatturapa_attachment, FatturaBody, partn "journal_id": purchase_journal.id, # 'origin': xmlData.datiOrdineAcquisto, "fiscal_position_id": fiscal_position.id, - "invoice_payment_term_id": partner.property_supplier_payment_term_id.id, + "invoice_payment_term_id": payment_term_id, "company_id": company.id, "fatturapa_attachment_in_id": fatturapa_attachment.id, "narration": comment, @@ -1314,10 +1280,6 @@ def invoiceCreate(self, fatt, fatturapa_attachment, FatturaBody, partner_id): # 2.5 self.set_attachments_data(FatturaBody, invoice) - self._addGlobalDiscount( - invoice.id, FatturaBody.DatiGenerali.DatiGeneraliDocumento - ) - if self.e_invoice_detail_level != "1": self.set_roundings(FatturaBody, invoice) @@ -1798,44 +1760,20 @@ def set_invoice_line_ids( return invoice_lines def check_invoice_amount(self, invoice, FatturaElettronicaBody): - dgd = FatturaElettronicaBody.DatiGenerali.DatiGeneraliDocumento - if dgd.ScontoMaggiorazione and dgd.ImportoTotaleDocumento: - # assuming that, if someone uses - # DatiGeneraliDocumento.ScontoMaggiorazione, also fills - # DatiGeneraliDocumento.ImportoTotaleDocumento - ImportoTotaleDocumento = float(dgd.ImportoTotaleDocumento) - if not float_is_zero( - invoice.amount_total - ImportoTotaleDocumento, precision_digits=2 - ): - self.log_inconsistency( - _( - "Bill total %(amount_total)s is different " - "from document total amount %(document_total_amount)s" - ) - % { - "amount_total": invoice.amount_total, - "document_total_amount": ImportoTotaleDocumento, - } - ) - else: - # else, we can only check DatiRiepilogo if - # DatiGeneraliDocumento.ScontoMaggiorazione is not present, - # because otherwise DatiRiepilogo and odoo invoice total would - # differ - amount_untaxed = invoice.compute_xml_amount_untaxed(FatturaElettronicaBody) - if not float_is_zero( - invoice.amount_untaxed - amount_untaxed, precision_digits=2 - ): - self.log_inconsistency( - _( - "Computed amount untaxed %(amount_untaxed)s is " - "different from summary data %(summary_data)s" - ) - % { - "amount_untaxed": invoice.amount_untaxed, - "summary_data": amount_untaxed, - } + amount_untaxed = invoice.compute_xml_amount_untaxed(FatturaElettronicaBody) + if not float_is_zero( + invoice.amount_untaxed - amount_untaxed, precision_digits=2 + ): + self.log_inconsistency( + _( + "Computed amount untaxed %(amount_untaxed)s is " + "different from summary data %(summary_data)s" ) + % { + "amount_untaxed": invoice.amount_untaxed, + "summary_data": amount_untaxed, + } + ) def create_and_get_line_id(self, invoice_line_ids, invoice_line_model, upd_vals): invoice_line_id = ( diff --git a/l10n_it_fatturapa_out/README.rst b/l10n_it_fatturapa_out/README.rst index dbfe752c3be6..6ed87ee93a69 100644 --- a/l10n_it_fatturapa_out/README.rst +++ b/l10n_it_fatturapa_out/README.rst @@ -7,7 +7,7 @@ ITA - Fattura elettronica - Emissione !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:88527618f59f6dc6f397b130ca6cc94d609cdd679ab135c5cd5ca1aa53d87208 + !! source digest: sha256:9e1960be2facfa1ba73093dcb4f77e96e2db6a2ffd58247841b6f1c2a155e9e6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/l10n_it_fatturapa_out/__manifest__.py b/l10n_it_fatturapa_out/__manifest__.py index 7a30bab87d6c..06146b3d3204 100644 --- a/l10n_it_fatturapa_out/__manifest__.py +++ b/l10n_it_fatturapa_out/__manifest__.py @@ -8,7 +8,7 @@ { "name": "ITA - Fattura elettronica - Emissione", - "version": "16.0.1.4.0", + "version": "16.0.1.4.1", "development_status": "Beta", "category": "Localization/Italy", "summary": "Emissione fatture elettroniche", diff --git a/l10n_it_fatturapa_out/static/description/index.html b/l10n_it_fatturapa_out/static/description/index.html index 587ca9bca2b7..a97e8c91e699 100644 --- a/l10n_it_fatturapa_out/static/description/index.html +++ b/l10n_it_fatturapa_out/static/description/index.html @@ -367,7 +367,7 @@

ITA - Fattura elettronica - Emissione

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:88527618f59f6dc6f397b130ca6cc94d609cdd679ab135c5cd5ca1aa53d87208 +!! source digest: sha256:9e1960be2facfa1ba73093dcb4f77e96e2db6a2ffd58247841b6f1c2a155e9e6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Italiano

diff --git a/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py b/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py index dc73818baade..1c50e77afcf2 100644 --- a/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py +++ b/l10n_it_fatturapa_out/wizard/wizard_export_fatturapa.py @@ -14,6 +14,7 @@ from odoo import api, fields, models from odoo.exceptions import UserError +from odoo.tools import float_is_zero from odoo.tools.translate import _ from odoo.addons.l10n_it_account.tools.account_tools import encode_for_export @@ -146,14 +147,28 @@ def _key(tax_id): tax_line_id = tax_id.tax_line_id aliquota = format_numbers(tax_line_id.amount) key = _key(tax_line_id) - out_computed[key] = { - "AliquotaIVA": aliquota, - "Natura": tax_line_id.kind_id.code, - # 'Arrotondamento':'', - "ImponibileImporto": tax_id.tax_base_amount, - "Imposta": abs(tax_id.balance), - "EsigibilitaIVA": tax_line_id.payability, - } + tax_amount = 0 + dp = self.env["decimal.precision"].precision_get("Account") + if invoice.move_type == "out_invoice": + if float_is_zero(tax_id.credit, dp) and tax_id.debit: + tax_amount = -tax_id.balance + if tax_id.credit and float_is_zero(tax_id.debit, dp): + tax_amount = abs(tax_id.balance) + else: + tax_amount = abs(tax_id.balance) + if key not in out_computed: + out_computed[key] = { + "AliquotaIVA": aliquota, + "Natura": tax_line_id.kind_id.code, + # 'Arrotondamento':'', + "ImponibileImporto": tax_id.tax_base_amount, + "Imposta": tax_amount, + "EsigibilitaIVA": tax_line_id.payability, + } + else: + out_computed[key]["ImponibileImporto"] += tax_id.tax_base_amount + out_computed[key]["Imposta"] += tax_amount + if tax_line_id.law_reference: out_computed[key]["RiferimentoNormativo"] = encode_for_export( tax_line_id.law_reference, 100 diff --git a/l10n_it_financial_statements_report/i18n/it.po b/l10n_it_financial_statements_report/i18n/it.po index 46fa90922cd5..d81651344492 100644 --- a/l10n_it_financial_statements_report/i18n/it.po +++ b/l10n_it_financial_statements_report/i18n/it.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-07-13 14:52+0000\n" -"PO-Revision-Date: 2024-09-18 16:06+0000\n" +"PO-Revision-Date: 2024-10-22 10:06+0000\n" "Last-Translator: mymage \n" "Language-Team: \n" "Language: it\n" diff --git a/l10n_it_intrastat_statement/README.rst b/l10n_it_intrastat_statement/README.rst index 8bede282f2cb..453ac5808122 100644 --- a/l10n_it_intrastat_statement/README.rst +++ b/l10n_it_intrastat_statement/README.rst @@ -7,7 +7,7 @@ ITA - Dichiarazione Intrastat !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:76539d27277c5c83974426a191e73eb11e823b171b620c00d3a8caf9fd93b65b + !! source digest: sha256:4e563c31c34170a044f6605c25da93fcad71b091a4909e49d0097e04bd2daccc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/l10n_it_intrastat_statement/__manifest__.py b/l10n_it_intrastat_statement/__manifest__.py index ccd42567ddfd..b33a31f5a459 100644 --- a/l10n_it_intrastat_statement/__manifest__.py +++ b/l10n_it_intrastat_statement/__manifest__.py @@ -3,7 +3,7 @@ { "name": "ITA - Dichiarazione Intrastat", - "version": "16.0.1.1.0", + "version": "16.0.1.2.0", "category": "Account", "summary": "Dichiarazione Intrastat per l'Agenzia delle Dogane", "author": "Openforce, Link IT srl, Agile Business Group, " @@ -23,8 +23,12 @@ "report/report_intrastat_mod1.xml", "report/intrastat_mod1_bis.xml", "report/intrastat_mod1_ter.xml", + "report/report_intrastat_mod1_quater.xml", + "report/report_intrastat_mod1_quinquies.xml", "report/report_intrastat_mod2.xml", "report/report_intrastat_mod2_bis.xml", + "report/report_intrastat_mod2_quater.xml", + "report/report_intrastat_mod2_quinquies.xml", "report/reports.xml", ], } diff --git a/l10n_it_intrastat_statement/i18n/es.po b/l10n_it_intrastat_statement/i18n/es.po index b58449ff7c69..6279c6e1ba88 100644 --- a/l10n_it_intrastat_statement/i18n/es.po +++ b/l10n_it_intrastat_statement/i18n/es.po @@ -413,6 +413,16 @@ msgstr "Modelo Bis INTRA-1" msgid "INTRA-1 Model" msgstr "Modelo INTRA-1" +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_quater +msgid "INTRA-1 Quater Model" +msgstr "" + +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_quinquies +msgid "INTRA-1 Quinquies Model" +msgstr "" + #. module: l10n_it_intrastat_statement #: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_ter msgid "INTRA-1 Ter Model" @@ -428,6 +438,16 @@ msgstr "Modelo Bis INTRA-2" msgid "INTRA-2 Model" msgstr "Modelo INTRA-2" +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod2_quater +msgid "INTRA-2 Quater Model" +msgstr "" + +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod2_quinquies +msgid "INTRA-2 Quinquies Model" +msgstr "" + #. module: l10n_it_intrastat_statement #: model_terms:ir.ui.view,arch_db:l10n_it_intrastat_statement.account_intrastat_statement_form_view msgid "INTRASTAT Statement" diff --git a/l10n_it_intrastat_statement/i18n/it.po b/l10n_it_intrastat_statement/i18n/it.po index c1eb98d22792..2e0932a5d1bc 100644 --- a/l10n_it_intrastat_statement/i18n/it.po +++ b/l10n_it_intrastat_statement/i18n/it.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Odoo Server 12.0+e-20191007\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-11-12 11:04+0000\n" -"PO-Revision-Date: 2023-10-13 10:39+0000\n" +"PO-Revision-Date: 2024-10-05 17:06+0000\n" "Last-Translator: mymage \n" "Language-Team: \n" "Language: it\n" @@ -15,7 +15,7 @@ msgstr "" "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" +"X-Generator: Weblate 5.6.2\n" #. module: l10n_it_intrastat_statement #: model:ir.model.fields,field_description:l10n_it_intrastat_statement.field_account_intrastat_statement_purchase_section1__additional_units_required @@ -416,6 +416,16 @@ msgstr "Modello INTRA-1 bis" msgid "INTRA-1 Model" msgstr "Modello INTRA-1" +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_quater +msgid "INTRA-1 Quater Model" +msgstr "Modello INTRA-1 quater" + +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_quinquies +msgid "INTRA-1 Quinquies Model" +msgstr "Modello INTRA-1 quinquies" + #. module: l10n_it_intrastat_statement #: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_ter msgid "INTRA-1 Ter Model" @@ -431,6 +441,16 @@ msgstr "Modello INTRA-2 bis" msgid "INTRA-2 Model" msgstr "Modello INTRA-2" +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod2_quater +msgid "INTRA-2 Quater Model" +msgstr "Modello INTRA-2 quater" + +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod2_quinquies +msgid "INTRA-2 Quinquies Model" +msgstr "Modello INTRA-2 quinquies" + #. module: l10n_it_intrastat_statement #: model_terms:ir.ui.view,arch_db:l10n_it_intrastat_statement.account_intrastat_statement_form_view msgid "INTRASTAT Statement" diff --git a/l10n_it_intrastat_statement/i18n/l10n_it_intrastat_statement.pot b/l10n_it_intrastat_statement/i18n/l10n_it_intrastat_statement.pot index e931103b1ad1..d33abcc4860b 100644 --- a/l10n_it_intrastat_statement/i18n/l10n_it_intrastat_statement.pot +++ b/l10n_it_intrastat_statement/i18n/l10n_it_intrastat_statement.pot @@ -409,6 +409,16 @@ msgstr "" msgid "INTRA-1 Model" msgstr "" +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_quater +msgid "INTRA-1 Quater Model" +msgstr "" + +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_quinquies +msgid "INTRA-1 Quinquies Model" +msgstr "" + #. module: l10n_it_intrastat_statement #: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod1_ter msgid "INTRA-1 Ter Model" @@ -424,6 +434,16 @@ msgstr "" msgid "INTRA-2 Model" msgstr "" +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod2_quater +msgid "INTRA-2 Quater Model" +msgstr "" + +#. module: l10n_it_intrastat_statement +#: model:ir.actions.report,name:l10n_it_intrastat_statement.print_intrastat_mod2_quinquies +msgid "INTRA-2 Quinquies Model" +msgstr "" + #. module: l10n_it_intrastat_statement #: model_terms:ir.ui.view,arch_db:l10n_it_intrastat_statement.account_intrastat_statement_form_view msgid "INTRASTAT Statement" diff --git a/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section3.py b/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section3.py index f95e8a867f82..12590d69d250 100644 --- a/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section3.py +++ b/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section3.py @@ -21,6 +21,14 @@ class IntrastatStatementPurchaseSection3(models.Model): comodel_name="res.country", string="Payment Country" ) + def get_supply_method_key(self): + self.ensure_one() + return self.supply_method + + def get_payment_method_key(self): + self.ensure_one() + return self.payment_method + @api.model def get_section_number(self): return 3 diff --git a/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section4.py b/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section4.py index b4f3b7514a11..a608f44177cd 100644 --- a/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section4.py +++ b/l10n_it_intrastat_statement/models/intrastat_statement_purchase_section4.py @@ -32,6 +32,14 @@ class IntrastatStatementPurchaseSection4(models.Model): comodel_name="res.country", string="Payment Country" ) + def get_supply_method_key(self): + self.ensure_one() + return self.supply_method + + def get_payment_method_key(self): + self.ensure_one() + return self.payment_method + @api.model def get_section_number(self): return 4 diff --git a/l10n_it_intrastat_statement/models/intrastat_statement_sale_section3.py b/l10n_it_intrastat_statement/models/intrastat_statement_sale_section3.py index d3bc5072ad12..016d6aacbf26 100644 --- a/l10n_it_intrastat_statement/models/intrastat_statement_sale_section3.py +++ b/l10n_it_intrastat_statement/models/intrastat_statement_sale_section3.py @@ -23,6 +23,14 @@ class IntrastatStatementSaleSection3(models.Model): comodel_name="res.country", string="Payment Country" ) + def get_supply_method_key(self): + self.ensure_one() + return self.supply_method + + def get_payment_method_key(self): + self.ensure_one() + return self.payment_method + @api.model def get_section_number(self): return 3 diff --git a/l10n_it_intrastat_statement/models/intrastat_statement_sale_section4.py b/l10n_it_intrastat_statement/models/intrastat_statement_sale_section4.py index cfd56e0062b7..c0b147979a80 100644 --- a/l10n_it_intrastat_statement/models/intrastat_statement_sale_section4.py +++ b/l10n_it_intrastat_statement/models/intrastat_statement_sale_section4.py @@ -35,6 +35,14 @@ class IntrastatStatementSaleSection4(models.Model): help="The Adjustment is intended for cancellation", ) + def get_supply_method_key(self): + self.ensure_one() + return self.supply_method + + def get_payment_method_key(self): + self.ensure_one() + return self.payment_method + @api.model def get_section_number(self): return 4 diff --git a/l10n_it_intrastat_statement/report/intrastat_mod1_bis.xml b/l10n_it_intrastat_statement/report/intrastat_mod1_bis.xml index fb34b2e5bcc1..de49c1a0a59c 100644 --- a/l10n_it_intrastat_statement/report/intrastat_mod1_bis.xml +++ b/l10n_it_intrastat_statement/report/intrastat_mod1_bis.xml @@ -4,7 +4,13 @@ - + +
@@ -189,7 +195,7 @@
- +
diff --git a/l10n_it_intrastat_statement/report/intrastat_mod1_ter.xml b/l10n_it_intrastat_statement/report/intrastat_mod1_ter.xml index 503188c5a3d5..4b7990769f2e 100644 --- a/l10n_it_intrastat_statement/report/intrastat_mod1_ter.xml +++ b/l10n_it_intrastat_statement/report/intrastat_mod1_ter.xml @@ -8,7 +8,13 @@ - + +
@@ -179,7 +185,7 @@
- +
diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod1.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod1.xml index 25eb941e4343..2d8332fa3279 100644 --- a/l10n_it_intrastat_statement/report/report_intrastat_mod1.xml +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod1.xml @@ -4,7 +4,13 @@ - + +
@@ -248,7 +254,7 @@
- +
diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod1_quater.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod1_quater.xml new file mode 100644 index 000000000000..23ce762c90ab --- /dev/null +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod1_quater.xml @@ -0,0 +1,173 @@ + + + + diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod1_quinquies.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod1_quinquies.xml new file mode 100644 index 000000000000..8e0af4f37a0a --- /dev/null +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod1_quinquies.xml @@ -0,0 +1,201 @@ + + + + diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod2.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod2.xml index ceabc6e04600..1e59b01479cd 100644 --- a/l10n_it_intrastat_statement/report/report_intrastat_mod2.xml +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod2.xml @@ -4,7 +4,13 @@ - + +
@@ -247,7 +253,7 @@
- +
diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod2_bis.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod2_bis.xml index 517c692bd4d6..027476ae9b08 100644 --- a/l10n_it_intrastat_statement/report/report_intrastat_mod2_bis.xml +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod2_bis.xml @@ -4,7 +4,13 @@ - + +
@@ -197,7 +203,7 @@
-
+
diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod2_quater.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod2_quater.xml new file mode 100644 index 000000000000..09a6a94a10cb --- /dev/null +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod2_quater.xml @@ -0,0 +1,184 @@ + + + + diff --git a/l10n_it_intrastat_statement/report/report_intrastat_mod2_quinquies.xml b/l10n_it_intrastat_statement/report/report_intrastat_mod2_quinquies.xml new file mode 100644 index 000000000000..d2f16f910f79 --- /dev/null +++ b/l10n_it_intrastat_statement/report/report_intrastat_mod2_quinquies.xml @@ -0,0 +1,207 @@ + + + + diff --git a/l10n_it_intrastat_statement/report/reports.xml b/l10n_it_intrastat_statement/report/reports.xml index e0cb59f8cd2f..6f120f2f41b8 100644 --- a/l10n_it_intrastat_statement/report/reports.xml +++ b/l10n_it_intrastat_statement/report/reports.xml @@ -109,4 +109,72 @@ ref="l10n_it_intrastat_statement.no_header_format_a4_landscape" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_intrastat_statement/static/description/index.html b/l10n_it_intrastat_statement/static/description/index.html index f1ae87179faf..0106b5e19897 100644 --- a/l10n_it_intrastat_statement/static/description/index.html +++ b/l10n_it_intrastat_statement/static/description/index.html @@ -367,7 +367,7 @@

ITA - Dichiarazione Intrastat

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:76539d27277c5c83974426a191e73eb11e823b171b620c00d3a8caf9fd93b65b +!! source digest: sha256:4e563c31c34170a044f6605c25da93fcad71b091a4909e49d0097e04bd2daccc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Italiano

diff --git a/l10n_it_riba/README.rst b/l10n_it_riba/README.rst index 1d61ff554f43..ea5b7f5d322f 100644 --- a/l10n_it_riba/README.rst +++ b/l10n_it_riba/README.rst @@ -7,7 +7,7 @@ ITA - Ricevute bancarie !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:74f718c92239a411abd4ce9f3e04f8a8e295353684af9a1010e14be51bd05f6e + !! source digest: sha256:b8691095af61fc81315ba9c98c4a08a23d3df4999c032a31c7870adc1b45b5e9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -110,9 +110,15 @@ della RiBa non ancora scaduta. In maniera predefinita la data delle registrazioni dei pagamenti viene impostata con la data di scadenza della RiBa, ma è possibile modificarla -successivamente a pagamento effettivamente avvenuto selezionando la -registrazione dalla vista ed elenco ed eseguendo l'azione "Imposta data -di pagamento RiBa". +in due momenti: + +- durante la creazione del pagamento, cliccando su "Segna righe come + pagate" o su "Segna coma pagata" o usando l'azione "Registrazione + Riba a data di scadenza" e indicando una data nel campo + ``Data pagamento``, +- successivamente a pagamento effettivamente avvenuto selezionando la + registrazione dalla vista ed elenco ed eseguendo l'azione "Imposta + data di pagamento RiBa". Known issues / Roadmap ====================== diff --git a/l10n_it_riba/__manifest__.py b/l10n_it_riba/__manifest__.py index 123468db8722..a67c3f94aa2a 100644 --- a/l10n_it_riba/__manifest__.py +++ b/l10n_it_riba/__manifest__.py @@ -10,7 +10,7 @@ { "name": "ITA - Ricevute bancarie", - "version": "16.0.1.6.3", + "version": "16.0.1.7.0", "development_status": "Beta", "author": "Odoo Community Association (OCA)", "category": "Localization/Italy", @@ -44,6 +44,7 @@ "views/riba_detail_view.xml", "views/wizard_presentation.xml", "views/wizard_due_date_settlement.xml", + "wizard/wizard_riba_multiple_payment_views.xml", ], "demo": ["demo/riba_demo.xml"], "installable": True, diff --git a/l10n_it_riba/i18n/it.po b/l10n_it_riba/i18n/it.po index 24f4d7d587fc..466cfc1fcbd1 100644 --- a/l10n_it_riba/i18n/it.po +++ b/l10n_it_riba/i18n/it.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-09-28 10:26+0000\n" -"PO-Revision-Date: 2024-09-11 09:06+0000\n" +"PO-Revision-Date: 2024-10-05 17:06+0000\n" "Last-Translator: mymage \n" "Language-Team: \n" "Language: it\n" @@ -121,6 +121,7 @@ msgstr "Al dopo incasso" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__total_amount #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__amount #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__amount +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_payment_multiple_view_form #: model_terms:ir.ui.view,arch_db:l10n_it_riba.slip_qweb #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_detail_riba_tree #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form @@ -236,6 +237,7 @@ msgstr "CUP" #: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_due_date_settlement #: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_issue_view #: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_past_due +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_payment_multiple_view_form #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form #: model_terms:ir.ui.view,arch_db:l10n_it_riba.wizard_presentation_riba msgid "Cancel" @@ -352,6 +354,7 @@ msgstr "Crea" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__create_uid +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__create_uid @@ -367,6 +370,7 @@ msgstr "Creato da" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__create_date +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__create_date @@ -454,6 +458,11 @@ msgstr "Valuta" msgid "Customer" msgstr "Cliente" +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__date +msgid "Date" +msgstr "Data" + #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_to_issue_tree msgid "Debit Total" @@ -474,6 +483,21 @@ msgstr "Servizio spese di incasso predefinito" msgid "Default Service for RiBa Collection Fees on invoice." msgstr "Servizio predefinito per le spese di incasso RiBa nella fattura." +#. module: l10n_it_riba +#: model:ir.model.fields,help:l10n_it_riba.field_riba_slip__date_paid +msgid "Default date for payments." +msgstr "Data predefinita per i pagamenti." + +#. module: l10n_it_riba +#: model:ir.model.fields,help:l10n_it_riba.field_riba_due_date_settlement__payment_date +#: model:ir.model.fields,help:l10n_it_riba.field_riba_payment_multiple__payment_date +msgid "" +"Defaults to the 'Payment date' in the RiBas.\n" +"If empty, the due date in each line will be used." +msgstr "" +"Il valore predefinito è 'Data di pagamento' nelle RiBa.\n" +"Se vuoto, verrà utilizzata la data di scadenza in ogni riga." + #. module: l10n_it_riba #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_configuration__name msgid "Description" @@ -493,6 +517,7 @@ msgstr "Dettaglio" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__display_name +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__display_name @@ -616,6 +641,7 @@ msgstr "IBAN" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__id +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__id @@ -640,6 +666,11 @@ msgstr "Se selezionata, nuovi messaggi richiedono attenzione." msgid "If checked, some messages have a delivery error." msgstr "Se selezionata, alcuni messaggi hanno un errore di consegna." +#. module: l10n_it_riba +#: model:ir.model.fields,help:l10n_it_riba.field_riba_past_due__date +msgid "If empty, the due date in the line will be used." +msgstr "Se vuoto, verrà utilizzata la data di scadenza indicata nella riga." + #. module: l10n_it_riba #: model:ir.model.fields.selection,name:l10n_it_riba.selection__riba_configuration__sbf_collection_type__immediate msgid "Immediate" @@ -768,6 +799,7 @@ msgstr "Lasciare vuoto per utilizzare la data corrente." #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date____last_update +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line____last_update @@ -783,6 +815,7 @@ msgstr "Ultima modifica il" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__write_uid +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__write_uid @@ -798,6 +831,7 @@ msgstr "Ultimo aggiornamento di" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__write_date +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__write_date @@ -820,11 +854,6 @@ msgstr "Allegato principale" msgid "Manage Past Due RiBas" msgstr "Gestione RiBa insolute" -#. module: l10n_it_riba -#: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form -msgid "Mark All as Settled" -msgstr "Segna tutte come pagate" - #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form msgid "Mark as Accepted" @@ -846,6 +875,11 @@ msgstr "Segna come insoluta" msgid "Mark as Settled" msgstr "Segna come pagata" +#. module: l10n_it_riba +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form +msgid "Mark lines as Settled" +msgstr "Segna le righe come pagate" + #. module: l10n_it_riba #: model:ir.model,name:l10n_it_riba.model_ir_ui_menu msgid "Menu" @@ -1073,7 +1107,19 @@ msgid "Past Dues" msgstr "Insoluti" #. module: l10n_it_riba +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_payment_multiple_view_form +msgid "Pay" +msgstr "Paga" + +#. module: l10n_it_riba +#: model:ir.model,name:l10n_it_riba.model_riba_payment_multiple +msgid "Pay multiple RiBa lines" +msgstr "Paga righe RiBa multiple" + +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_due_date_settlement__payment_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__date +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__payment_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__date_paid msgid "Payment Date" msgstr "Data pagamento" @@ -1098,6 +1144,13 @@ msgstr "Pagamenti" msgid "Please define a Settlement Journal." msgstr "Definire un registro pagamenti." +#. module: l10n_it_riba +#. odoo-python +#: code:addons/l10n_it_riba/wizard/wizard_riba_multiple_payment.py:0 +#, python-format +msgid "Please select the RiBa lines to be paid" +msgstr "Selezionare le righe RiBa da pagare" + #. module: l10n_it_riba #: model:ir.model.fields,field_description:l10n_it_riba.field_presentation_riba_issue__presentation_amount msgid "Presentation Amount" @@ -1300,6 +1353,12 @@ msgstr "RiBa da emettere" msgid "RiBa configuration to be used." msgstr "Configurazione RiBa da utilizzare." +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_due_date_settlement__riba_line_ids +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__riba_line_ids +msgid "RiBa lines to be paid" +msgstr "Righe RiBa da pagare" + #. module: l10n_it_riba #: model:ir.model,name:l10n_it_riba.model_riba_due_date_settlement msgid "Riba Due Date Settlement" @@ -1311,6 +1370,12 @@ msgstr "Registrazione Riba a data di scadenza" msgid "SIA Code" msgstr "Codice SIA" +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_due_date_settlement__riba_ids +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__riba_ids +msgid "Selected RiBas" +msgstr "RiBa selezionate" + #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.wizard_riba_payment_date msgid "Set RiBa Payment Date" @@ -1328,7 +1393,21 @@ msgstr "" #. module: l10n_it_riba #: model:ir.actions.server,name:l10n_it_riba.riba_line_settle_action_server msgid "Settle RiBa Line" -msgstr "Sistema riga RiBa" +msgstr "Paga riga RiBa" + +#. module: l10n_it_riba +#. odoo-python +#: code:addons/l10n_it_riba/models/riba.py:0 +#, python-format +msgid "Settle line" +msgstr "Paga riga" + +#. module: l10n_it_riba +#. odoo-python +#: code:addons/l10n_it_riba/models/riba.py:0 +#, python-format +msgid "Settle lines" +msgstr "Paga righe" #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_configuration_form @@ -1497,6 +1576,9 @@ msgstr "del" msgid "{line_name} for {month}-{year}" msgstr "{line_name} per {month}-{year}" +#~ msgid "Mark All as Settled" +#~ msgstr "Segna tutte come pagate" + #~ msgid "SMS Delivery error" #~ msgstr "Errore consegna SMS" diff --git a/l10n_it_riba/i18n/l10n_it_riba.pot b/l10n_it_riba/i18n/l10n_it_riba.pot index 480a8bf94ac4..8bee3bc3e677 100644 --- a/l10n_it_riba/i18n/l10n_it_riba.pot +++ b/l10n_it_riba/i18n/l10n_it_riba.pot @@ -109,6 +109,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__total_amount #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__amount #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__amount +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_payment_multiple_view_form #: model_terms:ir.ui.view,arch_db:l10n_it_riba.slip_qweb #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_detail_riba_tree #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form @@ -220,6 +221,7 @@ msgstr "" #: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_due_date_settlement #: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_issue_view #: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_past_due +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_payment_multiple_view_form #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form #: model_terms:ir.ui.view,arch_db:l10n_it_riba.wizard_presentation_riba msgid "Cancel" @@ -328,6 +330,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__create_uid +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__create_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__create_uid @@ -343,6 +346,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__create_date +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__create_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__create_date @@ -429,6 +433,11 @@ msgstr "" msgid "Customer" msgstr "" +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__date +msgid "Date" +msgstr "" + #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_to_issue_tree msgid "Debit Total" @@ -449,6 +458,19 @@ msgstr "" msgid "Default Service for RiBa Collection Fees on invoice." msgstr "" +#. module: l10n_it_riba +#: model:ir.model.fields,help:l10n_it_riba.field_riba_slip__date_paid +msgid "Default date for payments." +msgstr "" + +#. module: l10n_it_riba +#: model:ir.model.fields,help:l10n_it_riba.field_riba_due_date_settlement__payment_date +#: model:ir.model.fields,help:l10n_it_riba.field_riba_payment_multiple__payment_date +msgid "" +"Defaults to the 'Payment date' in the RiBas.\n" +"If empty, the due date in each line will be used." +msgstr "" + #. module: l10n_it_riba #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_configuration__name msgid "Description" @@ -468,6 +490,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__display_name +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__display_name #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__display_name @@ -591,6 +614,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__id +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__id #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__id @@ -615,6 +639,11 @@ msgstr "" msgid "If checked, some messages have a delivery error." msgstr "" +#. module: l10n_it_riba +#: model:ir.model.fields,help:l10n_it_riba.field_riba_past_due__date +msgid "If empty, the due date in the line will be used." +msgstr "" + #. module: l10n_it_riba #: model:ir.model.fields.selection,name:l10n_it_riba.selection__riba_configuration__sbf_collection_type__immediate msgid "Immediate" @@ -742,6 +771,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date____last_update +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line____last_update #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line____last_update @@ -757,6 +787,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__write_uid +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__write_uid #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__write_uid @@ -772,6 +803,7 @@ msgstr "" #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_issue__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_past_due__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__write_date +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_line__write_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip_move_line__write_date @@ -794,11 +826,6 @@ msgstr "" msgid "Manage Past Due RiBas" msgstr "" -#. module: l10n_it_riba -#: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form -msgid "Mark All as Settled" -msgstr "" - #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form msgid "Mark as Accepted" @@ -820,6 +847,11 @@ msgstr "" msgid "Mark as Settled" msgstr "" +#. module: l10n_it_riba +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_slip_form +msgid "Mark lines as Settled" +msgstr "" + #. module: l10n_it_riba #: model:ir.model,name:l10n_it_riba.model_ir_ui_menu msgid "Menu" @@ -1049,7 +1081,19 @@ msgid "Past Dues" msgstr "" #. module: l10n_it_riba +#: model_terms:ir.ui.view,arch_db:l10n_it_riba.riba_payment_multiple_view_form +msgid "Pay" +msgstr "" + +#. module: l10n_it_riba +#: model:ir.model,name:l10n_it_riba.model_riba_payment_multiple +msgid "Pay multiple RiBa lines" +msgstr "" + +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_due_date_settlement__payment_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_date__date +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__payment_date #: model:ir.model.fields,field_description:l10n_it_riba.field_riba_slip__date_paid msgid "Payment Date" msgstr "" @@ -1074,6 +1118,13 @@ msgstr "" msgid "Please define a Settlement Journal." msgstr "" +#. module: l10n_it_riba +#. odoo-python +#: code:addons/l10n_it_riba/wizard/wizard_riba_multiple_payment.py:0 +#, python-format +msgid "Please select the RiBa lines to be paid" +msgstr "" + #. module: l10n_it_riba #: model:ir.model.fields,field_description:l10n_it_riba.field_presentation_riba_issue__presentation_amount msgid "Presentation Amount" @@ -1276,6 +1327,12 @@ msgstr "" msgid "RiBa configuration to be used." msgstr "" +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_due_date_settlement__riba_line_ids +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__riba_line_ids +msgid "RiBa lines to be paid" +msgstr "" + #. module: l10n_it_riba #: model:ir.model,name:l10n_it_riba.model_riba_due_date_settlement msgid "Riba Due Date Settlement" @@ -1287,6 +1344,12 @@ msgstr "" msgid "SIA Code" msgstr "" +#. module: l10n_it_riba +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_due_date_settlement__riba_ids +#: model:ir.model.fields,field_description:l10n_it_riba.field_riba_payment_multiple__riba_ids +msgid "Selected RiBas" +msgstr "" + #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.wizard_riba_payment_date msgid "Set RiBa Payment Date" @@ -1304,6 +1367,20 @@ msgstr "" msgid "Settle RiBa Line" msgstr "" +#. module: l10n_it_riba +#. odoo-python +#: code:addons/l10n_it_riba/models/riba.py:0 +#, python-format +msgid "Settle line" +msgstr "" + +#. module: l10n_it_riba +#. odoo-python +#: code:addons/l10n_it_riba/models/riba.py:0 +#, python-format +msgid "Settle lines" +msgstr "" + #. module: l10n_it_riba #: model_terms:ir.ui.view,arch_db:l10n_it_riba.view_riba_configuration_form msgid "Settlement" diff --git a/l10n_it_riba/models/riba.py b/l10n_it_riba/models/riba.py index 445f7c29bb41..4f55ac79eb53 100644 --- a/l10n_it_riba/models/riba.py +++ b/l10n_it_riba/models/riba.py @@ -96,7 +96,16 @@ def _compute_total_amount(self): ) date_accepted = fields.Date("Acceptance Date") date_credited = fields.Date("Credit Date") - date_paid = fields.Date("Payment Date", readonly=True) + date_paid = fields.Date( + string="Payment Date", + help="Default date for payments.", + readonly=True, + states={ + "credited": [ + ("readonly", False), + ], + }, + ) date_past_due = fields.Date("Past Due Date", readonly=True) company_id = fields.Many2one( "res.company", @@ -186,10 +195,18 @@ def riba_cancel(self): slip.state = "cancel" def settle_all_line(self): - for riba_list in self: - for line in riba_list.line_ids: - if line.state == "credited": - line.riba_line_settlement() + payment_wizard_action = ( + self.env["riba.payment.multiple"] + .with_context( + active_ids=self.ids, + ) + .get_formview_action() + ) + payment_wizard_action.update( + name=_("Settle lines"), + target="new", + ) + return payment_wizard_action @api.onchange("date_accepted", "date_credited") def _onchange_date(self): @@ -468,7 +485,26 @@ def confirm(self): if not line.slip_id.date_accepted: line.slip_id.date_accepted = fields.Date.context_today(self) - def riba_line_settlement(self): + def button_settle(self): + payment_wizard_action = ( + self.env["riba.payment.multiple"] + .with_context( + active_ids=self.slip_id.ids, + default_riba_line_ids=self.ids, + ) + .get_formview_action() + ) + payment_wizard_action.update( + name=_("Settle line"), + target="new", + ) + return payment_wizard_action + + def riba_line_settlement(self, date=None): + """Create payment the acceptance move of each line in `self`. + + :param date: The created payment's date. + """ for riba_line in self: if not riba_line.slip_id.config_id.settlement_journal_id: raise UserError(_("Please define a Settlement Journal.")) @@ -491,12 +527,13 @@ def riba_line_settlement(self): riba_line.slip_id.name, riba_line.partner_id.name, ) + move_date = date or riba_line.due_date.strftime("%Y-%m-%d") settlement_move = move_model.create( { "journal_id": ( riba_line.slip_id.config_id.settlement_journal_id.id ), - "date": riba_line.due_date.strftime("%Y-%m-%d"), + "date": move_date, "ref": move_ref, } ) diff --git a/l10n_it_riba/readme/USAGE.md b/l10n_it_riba/readme/USAGE.md index 6f6ee0edb805..ba4b75e29b9d 100644 --- a/l10n_it_riba/readme/USAGE.md +++ b/l10n_it_riba/readme/USAGE.md @@ -25,7 +25,11 @@ esposizione, cioè l'importo dovuto dal cliente a fronte dell'emissione della RiBa non ancora scaduta. In maniera predefinita la data delle registrazioni dei pagamenti viene -impostata con la data di scadenza della RiBa, ma è possibile modificarla -successivamente a pagamento effettivamente avvenuto selezionando la +impostata con la data di scadenza della RiBa, ma è possibile modificarla in due momenti: +- durante la creazione del pagamento, + cliccando su "Segna righe come pagate" o su "Segna coma pagata" + o usando l'azione "Registrazione Riba a data di scadenza" + e indicando una data nel campo `Data pagamento`, +- successivamente a pagamento effettivamente avvenuto selezionando la registrazione dalla vista ed elenco ed eseguendo l'azione "Imposta data di pagamento RiBa". diff --git a/l10n_it_riba/security/ir.model.access.csv b/l10n_it_riba/security/ir.model.access.csv index 8d66609cbe72..e5aae483dd67 100644 --- a/l10n_it_riba/security/ir.model.access.csv +++ b/l10n_it_riba/security/ir.model.access.csv @@ -20,3 +20,4 @@ access_riba_file_export,riba_file_export,model_riba_file_export,account.group_ac access_presentation_riba_issue,access_presentation_riba_issue,model_presentation_riba_issue,account.group_account_invoice,1,1,1,1 access_riba_due_date_settlement,riba_due_date_settlement,model_riba_due_date_settlement,account.group_account_invoice,1,1,1,1 access_riba_payment_date,riba_payment_date,model_riba_payment_date,account.group_account_invoice,1,1,1,1 +access_riba_multiple_payment_date,Full access to Pay multiple RiBa lines,model_riba_payment_multiple,account.group_account_invoice,1,1,1,1 diff --git a/l10n_it_riba/static/description/index.html b/l10n_it_riba/static/description/index.html index f24fa845a497..fa83d24cf7f9 100644 --- a/l10n_it_riba/static/description/index.html +++ b/l10n_it_riba/static/description/index.html @@ -367,7 +367,7 @@

ITA - Ricevute bancarie

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:74f718c92239a411abd4ce9f3e04f8a8e295353684af9a1010e14be51bd05f6e +!! source digest: sha256:b8691095af61fc81315ba9c98c4a08a23d3df4999c032a31c7870adc1b45b5e9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Italiano

@@ -447,9 +447,16 @@

Usage

della RiBa non ancora scaduta.

In maniera predefinita la data delle registrazioni dei pagamenti viene impostata con la data di scadenza della RiBa, ma è possibile modificarla -successivamente a pagamento effettivamente avvenuto selezionando la -registrazione dalla vista ed elenco ed eseguendo l’azione “Imposta data -di pagamento RiBa”.

+in due momenti:

+
    +
  • durante la creazione del pagamento, cliccando su “Segna righe come +pagate” o su “Segna coma pagata” o usando l’azione “Registrazione +Riba a data di scadenza” e indicando una data nel campo +Data pagamento,
  • +
  • successivamente a pagamento effettivamente avvenuto selezionando la +registrazione dalla vista ed elenco ed eseguendo l’azione “Imposta +data di pagamento RiBa”.
  • +

Known issues / Roadmap

diff --git a/l10n_it_riba/tests/riba_common.py b/l10n_it_riba/tests/riba_common.py index 876724a935d0..65f05b47f133 100644 --- a/l10n_it_riba/tests/riba_common.py +++ b/l10n_it_riba/tests/riba_common.py @@ -315,6 +315,7 @@ def create_config(self, sbf_collection_type): "past_due_journal_id": self.bank_journal.id, "overdue_effects_account_id": self.past_due_account.id, "protest_charge_account_id": self.expenses_account.id, + "settlement_journal_id": self.bank_journal.id, } ) diff --git a/l10n_it_riba/tests/test_riba.py b/l10n_it_riba/tests/test_riba.py index d700f1d31615..404c7455b520 100644 --- a/l10n_it_riba/tests/test_riba.py +++ b/l10n_it_riba/tests/test_riba.py @@ -5,6 +5,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import base64 +import datetime import os from odoo.exceptions import UserError @@ -764,3 +765,77 @@ def test_riba_inv_no_bank(self): ), err_msg, ) + + def test_riba_payment_date_multiple_lines(self): + """A specific date can be set to pay multiple RiBa lines.""" + # Arrange + company = self.env.company + payment_date = datetime.date(2020, month=1, day=1) + payment_term = self.payment_term2 + riba_configuration = self.riba_config_sbf_immediate + product = self.product1 + partner = self.partner + company.due_cost_service_id = self.service_due_cost + + invoice_form = Form( + self.env["account.move"].with_context( + default_move_type="out_invoice", + default_name="Test invoice", + ) + ) + invoice_form.partner_id = partner + invoice_form.invoice_payment_term_id = payment_term + invoice_form.riba_partner_bank_id = first(partner.bank_ids) + with invoice_form.invoice_line_ids.new() as line: + line.product_id = product + invoice = invoice_form.save() + invoice.action_post() + + to_issue_action = self.env.ref("l10n_it_riba.action_riba_to_issue") + to_issue_records = self.env[to_issue_action.res_model].search( + safe_eval.safe_eval(to_issue_action.domain) + ) + invoice_to_issue_records = to_issue_records & invoice.line_ids + self.assertTrue(invoice_to_issue_records) + + issue_wizard_model = self.env["riba.issue"].with_context( + active_model=invoice_to_issue_records._name, + active_ids=invoice_to_issue_records.ids, + ) + issue_wizard_form = Form(issue_wizard_model) + issue_wizard_form.configuration_id = riba_configuration + issue_wizard = issue_wizard_form.save() + issue_result = issue_wizard.create_list() + slip = self.env[issue_result["res_model"]].browse(issue_result["res_id"]) + + slip.confirm() + self.assertEqual(slip.state, "accepted") + + credit_wizard_action = self.env.ref("l10n_it_riba.riba_credit_action") + credit_wizard = ( + self.env[credit_wizard_action["res_model"]] + .with_context(active_id=slip.id) + .create( + { + "bank_amount": invoice.amount_total, + } + ) + ) + credit_wizard.create_move() + self.assertEqual(slip.state, "credited") + + # Act + payment_wizard_action = slip.settle_all_line() + payment_wizard_form = Form( + self.env[payment_wizard_action["res_model"]].with_context( + **payment_wizard_action["context"] + ) + ) + payment_wizard_form.payment_date = payment_date + payment_wizard = payment_wizard_form.save() + payment_wizard.pay() + + # Assert + self.assertEqual(slip.state, "paid") + payment_move = slip.payment_ids.move_id + self.assertEqual(payment_move.date, payment_date) diff --git a/l10n_it_riba/views/riba_view.xml b/l10n_it_riba/views/riba_view.xml index f614c83babaa..0d1af991346b 100644 --- a/l10n_it_riba/views/riba_view.xml +++ b/l10n_it_riba/views/riba_view.xml @@ -162,7 +162,7 @@