From 236a70ae7f67be73a1a676be27c0e1c16806c745 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Mon, 7 Dec 2020 10:45:41 +0100 Subject: [PATCH 01/20] [ADD] sale_payment_sheet: New module --- sale_payment_sheet/README.rst | 111 ++++ sale_payment_sheet/__init__.py | 3 + sale_payment_sheet/__manifest__.py | 28 + sale_payment_sheet/i18n/es.po | 551 ++++++++++++++++++ .../i18n/sale_payment_sheet.pot | 542 +++++++++++++++++ sale_payment_sheet/models/__init__.py | 3 + sale_payment_sheet/models/res_users.py | 13 + .../models/sale_payment_sheet.py | 279 +++++++++ sale_payment_sheet/readme/CONFIGURE.rst | 4 + sale_payment_sheet/readme/CONTRIBUTORS.rst | 4 + sale_payment_sheet/readme/DESCRIPTION.rst | 2 + sale_payment_sheet/readme/USAGE.rst | 22 + .../report_sale_payment_sheet_summary.xml | 91 +++ .../report/sale_payment_sheet_report.xml | 12 + .../security/ir.model.access.csv | 5 + sale_payment_sheet/security/security.xml | 35 ++ .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 459 +++++++++++++++ sale_payment_sheet/tests/__init__.py | 3 + .../tests/test_sale_payment_sheet.py | 137 +++++ sale_payment_sheet/views/res_users_views.xml | 16 + .../views/sale_payment_sheet_menu.xml | 70 +++ .../views/sale_payment_sheet_views.xml | 170 ++++++ sale_payment_sheet/wizards/__init__.py | 3 + .../wizards/sale_invoice_payment.py | 95 +++ .../wizards/sale_invoice_payment_view.xml | 38 ++ 26 files changed, 2696 insertions(+) create mode 100644 sale_payment_sheet/README.rst create mode 100644 sale_payment_sheet/__init__.py create mode 100644 sale_payment_sheet/__manifest__.py create mode 100644 sale_payment_sheet/i18n/es.po create mode 100644 sale_payment_sheet/i18n/sale_payment_sheet.pot create mode 100644 sale_payment_sheet/models/__init__.py create mode 100644 sale_payment_sheet/models/res_users.py create mode 100644 sale_payment_sheet/models/sale_payment_sheet.py create mode 100644 sale_payment_sheet/readme/CONFIGURE.rst create mode 100644 sale_payment_sheet/readme/CONTRIBUTORS.rst create mode 100644 sale_payment_sheet/readme/DESCRIPTION.rst create mode 100644 sale_payment_sheet/readme/USAGE.rst create mode 100644 sale_payment_sheet/report/report_sale_payment_sheet_summary.xml create mode 100644 sale_payment_sheet/report/sale_payment_sheet_report.xml create mode 100644 sale_payment_sheet/security/ir.model.access.csv create mode 100644 sale_payment_sheet/security/security.xml create mode 100644 sale_payment_sheet/static/description/icon.png create mode 100644 sale_payment_sheet/static/description/index.html create mode 100644 sale_payment_sheet/tests/__init__.py create mode 100644 sale_payment_sheet/tests/test_sale_payment_sheet.py create mode 100644 sale_payment_sheet/views/res_users_views.xml create mode 100644 sale_payment_sheet/views/sale_payment_sheet_menu.xml create mode 100644 sale_payment_sheet/views/sale_payment_sheet_views.xml create mode 100644 sale_payment_sheet/wizards/__init__.py create mode 100644 sale_payment_sheet/wizards/sale_invoice_payment.py create mode 100644 sale_payment_sheet/wizards/sale_invoice_payment_view.xml diff --git a/sale_payment_sheet/README.rst b/sale_payment_sheet/README.rst new file mode 100644 index 00000000000..2e8af10d759 --- /dev/null +++ b/sale_payment_sheet/README.rst @@ -0,0 +1,111 @@ +================== +Sale payment sheet +================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fsale--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/sale-workflow/tree/13.0/sale_payment_sheet + :alt: OCA/sale-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/sale-workflow-13-0/sale-workflow-13-0-sale_payment_sheet + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/167/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to commercial users register payments in a payment sheet. +This payment sheet will generate a bank statement when is confirmed. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to: + +#. Go to Settings > User and Companies > Users +#. Select the allowed journals to register payments + +Usage +===== + +To use this module, you need to: + +Create manual payment sheet: + +#. Go to Sales > Orders > Payments. +#. Create new payment sheet. + +You can pay invoices directly, to do this: + +#. Go to Sales > Orders > Invoices. +#. Select some invoices to pay. +#. Click on Action > Sale invoice payment. +#. A wizard will be displayed and select journal and put amount that you want + to pay. + +Payment one invoice: + +#. Go to Sales > Orders > Invoices. +#. Enter to invoice form. +#. Click "register payment". +#. A wizard will be displayed and select journal and put amount that you want + to pay. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `__: + + * Carlos Dauden + * Sergio Teruel + +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. + +This module is part of the `OCA/sale-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_payment_sheet/__init__.py b/sale_payment_sheet/__init__.py new file mode 100644 index 00000000000..9b2246d7e62 --- /dev/null +++ b/sale_payment_sheet/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import models +from . import wizards diff --git a/sale_payment_sheet/__manifest__.py b/sale_payment_sheet/__manifest__.py new file mode 100644 index 00000000000..dc449330ede --- /dev/null +++ b/sale_payment_sheet/__manifest__.py @@ -0,0 +1,28 @@ +# Copyright 2020 Tecnativa - Carlos Dauden +# Copyright 2020 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Sale payment sheet", + "summary": "Allow to create invoice payments to commercial users without " + "accounting permissions", + "version": "13.0.1.0.0", + "development_status": "Beta", + "category": "Account", + "website": "https://github.com/OCA/sale-workflow", + "author": "Tecnativa, Odoo Community Association (OCA)", + "maintainers": ["sergio-teruel"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["sale"], + "data": [ + "security/ir.model.access.csv", + "security/security.xml", + "report/report_sale_payment_sheet_summary.xml", + "report/sale_payment_sheet_report.xml", + "views/res_users_views.xml", + "views/sale_payment_sheet_views.xml", + "views/sale_payment_sheet_menu.xml", + "wizards/sale_invoice_payment_view.xml", + ], +} diff --git a/sale_payment_sheet/i18n/es.po b/sale_payment_sheet/i18n/es.po new file mode 100644 index 00000000000..49475286ea6 --- /dev/null +++ b/sale_payment_sheet/i18n/es.po @@ -0,0 +1,551 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_payment_sheet +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-09 08:37+0000\n" +"PO-Revision-Date: 2021-02-09 09:39+0100\n" +"Last-Translator: Sergio Teruel \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.3\n" + +#. module: sale_payment_sheet +#: model:ir.actions.report,print_report_name:sale_payment_sheet.action_report_sale_payment_sheet +msgid "'Payment sheet %s' % (object.name)" +msgstr "'Hoja de pagos %s' % (object.name)" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Page: " +msgstr "Página: " + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Sheet: " +msgstr " Hoja " + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Total: " +msgstr "Total: " + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_needaction +msgid "Action Needed" +msgstr "Necesaria acción" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_res_users__commercial_journal_ids +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__commercial_journal_ids +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__commercial_journal_ids +msgid "Allowed journals for commercial" +msgstr "Diarios permitidos" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__amount +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__amount +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Amount" +msgstr "Importe" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Amount Due" +msgstr "Importe adeudado" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_attachment_count +msgid "Attachment Count" +msgstr "Conteo de archivos adjuntos" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__statement_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Bank statement" +msgstr "Extracto bancario" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.sale_invoice_payment_wiz +msgid "Cancel" +msgstr "Cancelar" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__company_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__company_id +msgid "Company" +msgstr "Compañía" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__company_id +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__company_id +msgid "Company related to this journal" +msgstr "Compañía relacionada con este diario" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Confirm sheet" +msgstr "Confirmar hoja" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Confirmed" +msgstr "Confirmado" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__create_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__create_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__create_uid +msgid "Created by" +msgstr "Creado el" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__create_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__create_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__currency_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__date +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Date" +msgstr "Fecha" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Description" +msgstr "Descripción" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__display_name +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__display_name +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Draft" +msgstr "Borrador" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__reference +msgid "External Reference" +msgstr "Referencia Externa" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__failed_message_ids +msgid "Failed Messages" +msgstr "Mensajes Fallidos" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_follower_ids +msgid "Followers" +msgstr "Seguidores" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_channel_ids +msgid "Followers (Channels)" +msgstr "Seguidores (Canales)" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguidores (Empresas)" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet_line__transaction_type__full +msgid "Full payment" +msgstr "Completo" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__sequence +msgid "Gives the sequence order when displaying a list of payment sheet lines." +msgstr "" +"Indica el orden de secuencia cuando se muestra una lista de líneas de la " +"hoja de pagos." + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Group By" +msgstr "Agrupado por..." + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__id +msgid "ID" +msgstr "ID (Identificador)" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_needaction +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_unread +msgid "If checked, new messages require your attention." +msgstr "Si está marcado, hay nuevos mensajes que requieren su atención." + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "Si se encuentra marcado, algunos mensajes tienen error de envío." + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__invoice_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Invoice" +msgstr "Factura" + +#. module: sale_payment_sheet +#: model:ir.actions.act_window,name:sale_payment_sheet.action_invoice_sale_payment_sheet +#: model:ir.ui.menu,name:sale_payment_sheet.sale_payment_invoice +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Invoices" +msgstr "Facturas" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_is_follower +msgid "Is Follower" +msgstr "Es seguidor" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__journal_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__journal_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Journal" +msgstr "Diario" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__journal_currency_id +msgid "Journal's Currency" +msgstr "Moneda del diario" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__name +msgid "Label" +msgstr "Etiqueta" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz____last_update +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet____last_update +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__write_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__write_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__write_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__write_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_main_attachment_id +msgid "Main Attachment" +msgstr "Adjuntos principales" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_content +msgid "Message Content" +msgstr "Contenido del mensaje" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_has_error +msgid "Message Delivery error" +msgstr "Error de Envío de Mensaje" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_content +msgid "Message content, to be used only in searches" +msgstr "Contenido del mensaje, para usarse en búsquedas" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_ids +msgid "Messages" +msgstr "Messages" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__state__open +msgid "New" +msgstr "Nuevo" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__note +msgid "Notes" +msgstr "Notas" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_needaction_counter +msgid "Number of Actions" +msgstr "Número de acciones" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_has_error_counter +msgid "Number of errors" +msgstr "Errores" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "Número de mensajes que requieren una acción" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Número de mensajes con error de envío" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_unread_counter +msgid "Number of unread messages" +msgstr "Número de mensajes no leidos" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet_line__transaction_type__partial +msgid "Partial payment" +msgstr "Parcial" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__partner_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Partner" +msgstr "Empresa" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.sale_invoice_payment_wiz +msgid "Payment" +msgstr "Pagos" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Payment sheet" +msgstr "Hoja de pagos" + +#. module: sale_payment_sheet +#: model:ir.ui.menu,name:sale_payment_sheet.sale_payment_sheet_menu +msgid "Payments" +msgstr "Pagos" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__name +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__ref +msgid "Reference" +msgstr "Referencia" + +#. module: sale_payment_sheet +#: model_terms:ir.actions.act_window,help:sale_payment_sheet.action_sale_payment_sheet +msgid "Register a invoice payment (Salesman)" +msgstr "Registrar pago de factura (Comerciales)" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Reset to New" +msgstr "Reestablecer a Nuevo" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__user_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__user_id +msgid "Responsible" +msgstr "Responsable" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_sale_payment_sheet +msgid "Sale Payment Sheet" +msgstr "Hoja de pagos" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_sale_payment_sheet_line +msgid "Sale Payment Sheet Line" +msgstr "Líneas de la hoja de pagos" + +#. module: sale_payment_sheet +#: model:ir.actions.act_window,name:sale_payment_sheet.action_sale_invoice_payment_wiz +msgid "Sale invoice payment" +msgstr "Pago de facturas" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_sale_invoice_payment_wiz +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.sale_invoice_payment_wiz +msgid "Sale invoice payment wizard" +msgstr "Asistente de pago de factura" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_tree +msgid "Sale invoice payments" +msgstr "Pagos de facturas" + +#. module: sale_payment_sheet +#: model:ir.actions.act_window,name:sale_payment_sheet.action_sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Sale payment sheet" +msgstr "Hoja de pagos" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Sales Person" +msgstr "Comercial" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Search sale payment sheets" +msgstr "Búsqueda de pagos de facturas" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__sheet_id +msgid "Sheet" +msgstr "Hoja" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "Sheet %s confirmed, bank statement were created." +msgstr "Hoja %s confirmada, se crearon los extractos bancarios." + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__line_ids +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Sheet lines" +msgstr "Líneas" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__statement_line_id +msgid "Statement Line" +msgstr "Línea de extracto" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__state +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__state +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Status" +msgstr "Estado" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Tax Excluded" +msgstr "Impuesto no incluido" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "The amount of a cash transaction cannot be 0." +msgstr "El importe de una transacción en efectivo no puede ser 0." + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Total" +msgstr "Total" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Total Amount" +msgstr "Importe total" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__transaction_type +msgid "Transaction type" +msgstr "Tipo de transacción" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Transactions" +msgstr "Transacciones" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_unread +msgid "Unread Messages" +msgstr "Mensajes sin leer" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_unread_counter +msgid "Unread Messages Counter" +msgstr "Contador de mensajes no leidos" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_res_users +msgid "Users" +msgstr "Usuarios" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__journal_currency_id +msgid "Utility field to express amount currency" +msgstr "Campo útil para expresar importe en divisa." + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__state__confirm +msgid "Validated" +msgstr "Validado" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__website_message_ids +msgid "Website Messages" +msgstr "Mensajes del sitio web" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__website_message_ids +msgid "Website communication history" +msgstr "Historial de comunicaciones del sitio web" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "You can not delete a sheet if has related journal items." +msgstr "" +"No puede eliminar una hoja de pagos si tiene un extracto bancario " +"relacionado." + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "You can not delete payment lines if have related statement lines." +msgstr "" +"No puede eliminar líneas de pago si tienen una línea de extracto relacionada" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "You can not reopen a sheet that has any reconciled line." +msgstr "No puede reabrir una hoja de pagos si tiene alguna línea conciliada." + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_users_form +msgid "sale payment sheet" +msgstr "Hoja de pagos" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "sale payment sheet Summary" +msgstr "Resumen de pagos de facturas" + +#. module: sale_payment_sheet +#: model:ir.actions.report,name:sale_payment_sheet.action_report_sale_payment_sheet +msgid "sale payment sheet summary" +msgstr "Resumen de pagos de facturas" + +#~ msgid "Journal Entries" +#~ msgstr "Asientos contables" diff --git a/sale_payment_sheet/i18n/sale_payment_sheet.pot b/sale_payment_sheet/i18n/sale_payment_sheet.pot new file mode 100644 index 00000000000..a8a5776f85b --- /dev/null +++ b/sale_payment_sheet/i18n/sale_payment_sheet.pot @@ -0,0 +1,542 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_payment_sheet +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-09 08:37+0000\n" +"PO-Revision-Date: 2021-02-09 08:37+0000\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: sale_payment_sheet +#: model:ir.actions.report,print_report_name:sale_payment_sheet.action_report_sale_payment_sheet +msgid "'Payment sheet %s' % (object.name)" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Page: " +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Sheet: " +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Total: " +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_res_users__commercial_journal_ids +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__commercial_journal_ids +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__commercial_journal_ids +msgid "Allowed journals for commercial" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__amount +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__amount +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Amount" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Amount Due" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__statement_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Bank statement" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.sale_invoice_payment_wiz +msgid "Cancel" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__company_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__company_id +msgid "Company" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__company_id +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__company_id +msgid "Company related to this journal" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Confirm sheet" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Confirmed" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__create_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__create_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__create_uid +msgid "Created by" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__create_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__create_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__create_date +msgid "Created on" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__currency_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__currency_id +msgid "Currency" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__date +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Date" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Description" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__display_name +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__display_name +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__display_name +msgid "Display Name" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Draft" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__reference +msgid "External Reference" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__failed_message_ids +msgid "Failed Messages" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet_line__transaction_type__full +msgid "Full payment" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__sequence +msgid "" +"Gives the sequence order when displaying a list of payment sheet lines." +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Group By" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__id +msgid "ID" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_needaction +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_unread +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__invoice_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Invoice" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.actions.act_window,name:sale_payment_sheet.action_invoice_sale_payment_sheet +#: model:ir.ui.menu,name:sale_payment_sheet.sale_payment_invoice +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Invoices" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__journal_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__journal_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Journal" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__journal_currency_id +msgid "Journal's Currency" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__name +msgid "Label" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz____last_update +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet____last_update +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__write_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__write_uid +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__write_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__write_date +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__write_date +msgid "Last Updated on" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_content +msgid "Message Content" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_content +msgid "Message content, to be used only in searches" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_ids +msgid "Messages" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__state__open +msgid "New" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__note +msgid "Notes" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet_line__transaction_type__partial +msgid "Partial payment" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__partner_id +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "Partner" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.sale_invoice_payment_wiz +msgid "Payment" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Payment sheet" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.ui.menu,name:sale_payment_sheet.sale_payment_sheet_menu +msgid "Payments" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__name +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__ref +msgid "Reference" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.actions.act_window,help:sale_payment_sheet.action_sale_payment_sheet +msgid "Register a invoice payment (Salesman)" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Reset to New" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__user_id +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__user_id +msgid "Responsible" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_sale_payment_sheet +msgid "Sale Payment Sheet" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_sale_payment_sheet_line +msgid "Sale Payment Sheet Line" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.actions.act_window,name:sale_payment_sheet.action_sale_invoice_payment_wiz +msgid "Sale invoice payment" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_sale_invoice_payment_wiz +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.sale_invoice_payment_wiz +msgid "Sale invoice payment wizard" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_tree +msgid "Sale invoice payments" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.actions.act_window,name:sale_payment_sheet.action_sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Sale payment sheet" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Sales Person" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Search sale payment sheets" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__sequence +msgid "Sequence" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__sheet_id +msgid "Sheet" +msgstr "" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "Sheet %s confirmed, bank statement were created." +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__line_ids +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Sheet lines" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__statement_line_id +msgid "Statement Line" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__state +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__state +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_search +msgid "Status" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Tax Excluded" +msgstr "" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "The amount of a cash transaction cannot be 0." +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Total" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree +msgid "Total Amount" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__transaction_type +msgid "Transaction type" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form +msgid "Transactions" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model,name:sale_payment_sheet.model_res_users +msgid "Users" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__journal_currency_id +msgid "Utility field to express amount currency" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__state__confirm +msgid "Validated" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "You can not delete a sheet if has related journal items." +msgstr "" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "You can not delete payment lines if have related statement lines." +msgstr "" + +#. module: sale_payment_sheet +#: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 +#, python-format +msgid "You can not reopen a sheet that has any reconciled line." +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_users_form +msgid "sale payment sheet" +msgstr "" + +#. module: sale_payment_sheet +#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.report_sale_payment_sheet +msgid "sale payment sheet Summary" +msgstr "" + +#. module: sale_payment_sheet +#: model:ir.actions.report,name:sale_payment_sheet.action_report_sale_payment_sheet +msgid "sale payment sheet summary" +msgstr "" diff --git a/sale_payment_sheet/models/__init__.py b/sale_payment_sheet/models/__init__.py new file mode 100644 index 00000000000..3a56ee3e8b4 --- /dev/null +++ b/sale_payment_sheet/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import res_users +from . import sale_payment_sheet diff --git a/sale_payment_sheet/models/res_users.py b/sale_payment_sheet/models/res_users.py new file mode 100644 index 00000000000..dc7e5a3798c --- /dev/null +++ b/sale_payment_sheet/models/res_users.py @@ -0,0 +1,13 @@ +# Copyright 2020 Tecnativa - Carlos Dauden +# Copyright 2020 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + commercial_journal_ids = fields.Many2many( + comodel_name="account.journal", string="Allowed journals for commercial", + ) diff --git a/sale_payment_sheet/models/sale_payment_sheet.py b/sale_payment_sheet/models/sale_payment_sheet.py new file mode 100644 index 00000000000..f2888aa2a71 --- /dev/null +++ b/sale_payment_sheet/models/sale_payment_sheet.py @@ -0,0 +1,279 @@ +# Copyright 2020 Tecnativa - Carlos Dauden +# Copyright 2020 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError +from odoo.tools import float_compare + + +class SalePaymentSheet(models.Model): + _name = "sale.payment.sheet" + _description = "Sale Payment Sheet" + _order = "date desc, id desc" + _inherit = ["mail.thread"] + _check_company_auto = True + + name = fields.Char( + string="Reference", + states={"open": [("readonly", False)]}, + copy=False, + compute="_compute_name", + readonly=True, + store=True, + ) + reference = fields.Char( + string="External Reference", + states={"open": [("readonly", False)]}, + copy=False, + readonly=True, + ) + date = fields.Date( + required=True, + states={"confirm": [("readonly", True)]}, + index=True, + copy=False, + default=fields.Date.context_today, + ) + state = fields.Selection( + [("open", "New"), ("confirm", "Validated")], + string="Status", + required=True, + readonly=True, + copy=False, + default="open", + ) + currency_id = fields.Many2one( + "res.currency", compute="_compute_currency", string="Currency" + ) + journal_id = fields.Many2one( + "account.journal", + string="Journal", + required=True, + states={"confirm": [("readonly", True)]}, + default=lambda self: self._default_journal(), + ) + commercial_journal_ids = fields.Many2many(related="user_id.commercial_journal_ids") + company_id = fields.Many2one( + "res.company", + related="journal_id.company_id", + string="Company", + store=True, + readonly=True, + default=lambda self: self.env.company, + ) + line_ids = fields.One2many( + "sale.payment.sheet.line", + "sheet_id", + string="Sheet lines", + states={"confirm": [("readonly", True)]}, + copy=True, + ) + user_id = fields.Many2one( + "res.users", + string="Responsible", + required=False, + default=lambda self: self.env.user, + ) + statement_id = fields.Many2one( + comodel_name="account.bank.statement", string="Bank statement" + ) + + @api.model + def _default_journal(self): + return self.env.user.commercial_journal_ids[:1] + + @api.depends("journal_id.currency_id") + def _compute_currency(self): + for sheet in self: + sheet.currency_id = ( + sheet.journal_id.currency_id or sheet.company_id.currency_id + ) + + @api.depends("journal_id", "user_id", "date") + def _compute_name(self): + for sheet in self: + sheet.name = "{} - {} - {}".format( + sheet.date and sheet.date.strftime("%Y.%m.%d"), + sheet.journal_id.name, + sheet.user_id.name, + ) + + def unlink(self): + for sheet in self: + if sheet.state != "open": + raise UserError( + _("You can not delete a sheet if has related journal items.") + ) + return super().unlink() + + def button_confirm_sheet(self): + sheets = self.filtered(lambda r: r.state == "open") + BankStatement = self.env["account.bank.statement"].sudo() + BankStatementLine = self.env["account.bank.statement.line"].sudo() + for sheet in sheets: + statement = BankStatement.create( + { + "name": sheet.name, + "date": sheet.date, + "journal_id": sheet.journal_id.id, + "user_id": sheet.user_id.id, + } + ) + for line in sheet.line_ids: + vals = { + "name": line.name, + "date": line.date, + "amount": line.amount, + "partner_id": line.partner_id.id, + "ref": line.ref, + "note": line.note, + "sequence": line.sequence, + "statement_id": statement.id, + } + if line.invoice_id.type == "out_refund" and line.amount > 0.0: + # convert to negative amounts if user pays a refund out + # invoice with a positive amount. + vals["amount"] = -line.amount + statement_line = BankStatementLine.create(vals) + line.statement_line_id = statement_line + sheet.message_post( + body=_("Sheet %s confirmed, bank statement were created.") + % (statement.name,) + ) + sheet.write({"state": "confirm", "statement_id": statement.id}) + + def button_reopen(self): + self.ensure_one() + self_sudo = self.sudo() + if self_sudo.statement_id.line_ids.filtered("journal_entry_ids"): + raise UserError( + _("You can not reopen a sheet that has any reconciled line.") + ) + self_sudo.statement_id.unlink() + self.state = "open" + + def button_bank_statement(self): + """ + Action to open bank statement linked + """ + self.ensure_one() + return self.statement_id.get_formview_action() + + +class SalePaymentSheetLine(models.Model): + _name = "sale.payment.sheet.line" + _description = "Sale Payment Sheet Line" + _order = "sheet_id desc, date, sequence, id desc" + + name = fields.Char( + string="Label", compute="_compute_name", store=True, readonly=False + ) + date = fields.Date( + required=True, + default=lambda self: self._context.get("date", fields.Date.context_today(self)), + ) + sheet_id = fields.Many2one( + "sale.payment.sheet", + string="Sheet", + index=True, + required=True, + ondelete="cascade", + ) + statement_line_id = fields.Many2one( + "account.bank.statement.line", string="Statement Line", index=True + ) + amount = fields.Monetary( + compute="_compute_amount", + inverse="_inverse_amount", + currency_field="journal_currency_id", + store=True, + readonly=False, + ) + journal_currency_id = fields.Many2one( + "res.currency", + string="Journal's Currency", + related="sheet_id.currency_id", + help="Utility field to express amount currency", + readonly=True, + ) + partner_id = fields.Many2one("res.partner", string="Partner") + ref = fields.Char(string="Reference") + note = fields.Text(string="Notes") + sequence = fields.Integer( + index=True, + help="Gives the sequence order when displaying a list of payment sheet lines.", + default=1, + ) + company_id = fields.Many2one( + "res.company", + related="sheet_id.company_id", + string="Company", + store=True, + readonly=True, + ) + state = fields.Selection(related="sheet_id.state", string="Status", readonly=True) + invoice_id = fields.Many2one(comodel_name="account.move", string="Invoice") + transaction_type = fields.Selection( + [("partial", "Partial payment"), ("full", "Full payment")], + compute="_compute_transaction_type", + string="Transaction type", + ) + + @api.depends("amount", "invoice_id") + def _compute_transaction_type(self): + for line in self: + amount = ( + line.amount if line.invoice_id.type == "out_invoice" else -line.amount + ) + if float_compare( + amount, + line.invoice_id.amount_total, + precision_digits=line.sheet_id.currency_id.decimal_places, + ): + line.transaction_type = "partial" + else: + line.transaction_type = "full" + + @api.depends("sheet_id.user_id", "invoice_id", "transaction_type") + def _compute_name(self): + for line in self: + if not line.create_date: + line.create_date = fields.Datetime.now() + line.name = "[{}] - {} - {} - ({})".format( + fields.Datetime.context_timestamp(line, line.create_date).strftime( + "%H:%M" + ), + line.sheet_id.user_id.name, + line.invoice_id.name, + dict( + line._fields["transaction_type"]._description_selection(line.env) + ).get(line.transaction_type), + ) + + @api.depends("invoice_id") + def _compute_amount(self): + for line in self: + amount = line.invoice_id.amount_residual + line.amount = amount if line.invoice_id.type == "out_invoice" else -amount + + def _inverse_amount(self): + for line in self: + if line.invoice_id.type == "out_refund" and line.amount > 0.0: + line.amount = -line.amount + + @api.constrains("amount") + def _check_amount(self): + for line in self: + # Allow to enter sheet line with an amount of 0, + if line.journal_currency_id.is_zero(line.amount): + raise ValidationError( + _("The amount of a cash transaction cannot be 0.") + ) + + def unlink(self): + if self.filtered("statement_line_id"): + raise UserError( + _("You can not delete payment lines if have related statement lines.") + ) + return super().unlink() diff --git a/sale_payment_sheet/readme/CONFIGURE.rst b/sale_payment_sheet/readme/CONFIGURE.rst new file mode 100644 index 00000000000..49371d2be71 --- /dev/null +++ b/sale_payment_sheet/readme/CONFIGURE.rst @@ -0,0 +1,4 @@ +To configure this module, you need to: + +#. Go to Settings > User and Companies > Users +#. Select the allowed journals to register payments diff --git a/sale_payment_sheet/readme/CONTRIBUTORS.rst b/sale_payment_sheet/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..29ec7c3c9da --- /dev/null +++ b/sale_payment_sheet/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `Tecnativa `__: + + * Carlos Dauden + * Sergio Teruel diff --git a/sale_payment_sheet/readme/DESCRIPTION.rst b/sale_payment_sheet/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..bd730118c39 --- /dev/null +++ b/sale_payment_sheet/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows to commercial users register payments in a payment sheet. +This payment sheet will generate a bank statement when is confirmed. diff --git a/sale_payment_sheet/readme/USAGE.rst b/sale_payment_sheet/readme/USAGE.rst new file mode 100644 index 00000000000..9d2ad956007 --- /dev/null +++ b/sale_payment_sheet/readme/USAGE.rst @@ -0,0 +1,22 @@ +To use this module, you need to: + +Create manual payment sheet: + +#. Go to Sales > Orders > Payments. +#. Create new payment sheet. + +You can pay invoices directly, to do this: + +#. Go to Sales > Orders > Invoices. +#. Select some invoices to pay. +#. Click on Action > Sale invoice payment. +#. A wizard will be displayed and select journal and put amount that you want + to pay. + +Payment one invoice: + +#. Go to Sales > Orders > Invoices. +#. Enter to invoice form. +#. Click "register payment". +#. A wizard will be displayed and select journal and put amount that you want + to pay. diff --git a/sale_payment_sheet/report/report_sale_payment_sheet_summary.xml b/sale_payment_sheet/report/report_sale_payment_sheet_summary.xml new file mode 100644 index 00000000000..d5ef327a352 --- /dev/null +++ b/sale_payment_sheet/report/report_sale_payment_sheet_summary.xml @@ -0,0 +1,91 @@ + + + + diff --git a/sale_payment_sheet/report/sale_payment_sheet_report.xml b/sale_payment_sheet/report/sale_payment_sheet_report.xml new file mode 100644 index 00000000000..0af18681581 --- /dev/null +++ b/sale_payment_sheet/report/sale_payment_sheet_report.xml @@ -0,0 +1,12 @@ + + + + diff --git a/sale_payment_sheet/security/ir.model.access.csv b/sale_payment_sheet/security/ir.model.access.csv new file mode 100644 index 00000000000..6a4d46846de --- /dev/null +++ b/sale_payment_sheet/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_payment_sheet_salesman,access_sale_payment_sheet_salesman,model_sale_payment_sheet,sales_team.group_sale_salesman,1,1,1,1 +access_sale_payment_sheet_line_salesman,access_sale_payment_sheet_line_salesman,model_sale_payment_sheet_line,sales_team.group_sale_salesman,1,1,1,1 +access_sale_payment_sheet_accountant,access_sale_payment_sheet_accountant,model_sale_payment_sheet,account.group_account_invoice,1,1,1,1 +access_sale_payment_sheet_line_accountant,access_sale_payment_sheet_line_accountant,model_sale_payment_sheet_line,account.group_account_invoice,1,1,1,1 diff --git a/sale_payment_sheet/security/security.xml b/sale_payment_sheet/security/security.xml new file mode 100644 index 00000000000..d88c7b81933 --- /dev/null +++ b/sale_payment_sheet/security/security.xml @@ -0,0 +1,35 @@ + + + Sale payment sheet multi-company + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + + + + + Sale payment sheet account manager + + [] + + + + + + + + + Sale payment sheet salesman + + [('user_id','=', user.id)] + + + + + + + + diff --git a/sale_payment_sheet/static/description/icon.png b/sale_payment_sheet/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/sale_payment_sheet/static/description/index.html b/sale_payment_sheet/static/description/index.html new file mode 100644 index 00000000000..1f638f04519 --- /dev/null +++ b/sale_payment_sheet/static/description/index.html @@ -0,0 +1,459 @@ + + + + + + +Sale payment sheet + + + +
+

Sale payment sheet

+ + +

Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runbot

+

This module allows to commercial users register payments in a payment sheet. +This payment sheet will generate a bank statement when is confirmed.

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to Settings > User and Companies > Users
  2. +
  3. Select the allowed journals to register payments
  4. +
+
+
+

Usage

+

To use this module, you need to:

+

Create manual payment sheet:

+
    +
  1. Go to Sales > Orders > Payments.
  2. +
  3. Create new payment sheet.
  4. +
+

You can pay invoices directly, to do this:

+
    +
  1. Go to Sales > Orders > Invoices.
  2. +
  3. Select some invoices to pay.
  4. +
  5. Click on Action > Sale invoice payment.
  6. +
  7. A wizard will be displayed and select journal and put amount that you want +to pay.
  8. +
+

Payment one invoice:

+
    +
  1. Go to Sales > Orders > Invoices.
  2. +
  3. Enter to invoice form.
  4. +
  5. Click “register payment”.
  6. +
  7. A wizard will be displayed and select journal and put amount that you want +to pay.
  8. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/sale-workflow project on GitHub.

+

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

+
+
+
+ + diff --git a/sale_payment_sheet/tests/__init__.py b/sale_payment_sheet/tests/__init__.py new file mode 100644 index 00000000000..a66d7145ed6 --- /dev/null +++ b/sale_payment_sheet/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_sale_payment_sheet diff --git a/sale_payment_sheet/tests/test_sale_payment_sheet.py b/sale_payment_sheet/tests/test_sale_payment_sheet.py new file mode 100644 index 00000000000..77b990b6417 --- /dev/null +++ b/sale_payment_sheet/tests/test_sale_payment_sheet.py @@ -0,0 +1,137 @@ +# Copyright 2020 Tecnativa - Carlos Dauden +# Copyright 2020 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields +from odoo.exceptions import UserError +from odoo.tests import Form, SavepointCase + + +class TestSaleInvoicePayment(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.wizard_obj = cls.env["sale.invoice.payment.wiz"] + cls.SalePaymentSheet = cls.env["sale.payment.sheet"] + cls.partner = cls.env["res.partner"].create({"name": "Test partner"}) + cls.bank_journal = cls.env["account.journal"].create( + {"name": "Bank journal", "type": "bank", "code": "test"} + ) + account_type_income = cls.env.ref("account.data_account_type_revenue") + cls.account_invoice = cls.env["account.account"].create( + { + "code": "test", + "name": "Test account", + "user_type_id": account_type_income.id, + } + ) + cls.invoice1 = cls._create_invoice(cls) + cls.invoice2 = cls._create_invoice(cls) + (cls.invoice1 + cls.invoice2).action_post() + + def _create_invoice(self): + with Form( + self.env["account.move"].with_context(default_type="out_invoice") + ) as invoice_form: + invoice_form.partner_id = self.partner + with invoice_form.invoice_line_ids.new() as line_form: + line_form.name = "invoice test" + line_form.account_id = self.account_invoice + line_form.quantity = 1.0 + line_form.price_unit = 100.00 + return invoice_form.save() + + def test_payment_wizard(self): + PaymentWiz = self.env["sale.invoice.payment.wiz"].with_context( + active_model="account.move", active_ids=(self.invoice1 + self.invoice2).ids, + ) + with Form(PaymentWiz) as wiz_form: + wiz_form.journal_id = self.bank_journal + wiz_form.amount = 150.00 + wiz = wiz_form.save() + sheet = wiz.create_sale_invoice_payment_sheet() + self.assertEqual(len(sheet.line_ids), 2) + line_partial_payment = sheet.line_ids.filtered( + lambda ln: ln.transaction_type == "partial" + ) + self.assertTrue(line_partial_payment) + self.assertEqual(line_partial_payment.invoice_id, self.invoice2) + line_full_payment = sheet.line_ids.filtered( + lambda ln: ln.transaction_type == "full" + ) + self.assertTrue(line_full_payment) + self.assertEqual(line_full_payment.invoice_id, self.invoice1) + + def _create_payment_sheet(self): + with Form(self.SalePaymentSheet) as sheet_form: + sheet_form.journal_id = self.bank_journal + for index, invoice in enumerate(self.invoice1 + self.invoice2): + with sheet_form.line_ids.new() as line_sheet: + line_sheet.partner_id = self.partner + line_sheet.invoice_id = invoice + # Only write for partial amount payed, by default the + # amount line is total amount residual + if index > 0: + line_sheet.amount = 50.0 + return sheet_form.save() + + def test_manual_payment_sheet(self): + sheet = self._create_payment_sheet() + self.assertEqual(len(sheet.line_ids), 2) + line_partial_payment = sheet.line_ids.filtered( + lambda ln: ln.transaction_type == "partial" + ) + self.assertTrue(line_partial_payment) + self.assertEqual(line_partial_payment.invoice_id, self.invoice2) + line_full_payment = sheet.line_ids.filtered( + lambda ln: ln.transaction_type == "full" + ) + self.assertTrue(line_full_payment) + self.assertEqual(line_full_payment.invoice_id, self.invoice1) + self.assertEqual( + sheet.name, + "{} - {} - {}".format( + sheet.date.strftime("%Y.%m.%d"), + sheet.journal_id.name, + sheet.user_id.name, + ), + ) + self.assertEqual( + line_partial_payment.name, + "[{}] - {} - {} - ({})".format( + fields.Datetime.context_timestamp( + line_partial_payment, line_partial_payment.create_date + ).strftime("%H:%M"), + line_partial_payment.sheet_id.user_id.name, + line_partial_payment.invoice_id.name, + dict( + line_partial_payment._fields[ + "transaction_type" + ]._description_selection(line_partial_payment.env) + ).get(line_partial_payment.transaction_type), + ), + ) + + def test_payment_sheet_confirm(self): + sheet = self._create_payment_sheet() + sheet.button_confirm_sheet() + self.assertTrue(sheet.statement_id) + self.assertEqual(len(sheet.line_ids.mapped("statement_line_id")), 2) + + def test_payment_sheet_reopen(self): + sheet = self._create_payment_sheet() + sheet.button_confirm_sheet() + sheet.button_reopen() + self.assertFalse(sheet.statement_id) + + def test_payment_sheet_unlink(self): + sheet = self._create_payment_sheet() + sheet.button_confirm_sheet() + with self.assertRaises(UserError): + sheet.unlink() + + def test_payment_sheet_line_unlink(self): + sheet = self._create_payment_sheet() + sheet.button_confirm_sheet() + with self.assertRaises(UserError): + sheet.line_ids.unlink() diff --git a/sale_payment_sheet/views/res_users_views.xml b/sale_payment_sheet/views/res_users_views.xml new file mode 100644 index 00000000000..88a9cb489b2 --- /dev/null +++ b/sale_payment_sheet/views/res_users_views.xml @@ -0,0 +1,16 @@ + + + + res.users + + + + + + + + + + + + diff --git a/sale_payment_sheet/views/sale_payment_sheet_menu.xml b/sale_payment_sheet/views/sale_payment_sheet_menu.xml new file mode 100644 index 00000000000..0fd2d2a8151 --- /dev/null +++ b/sale_payment_sheet/views/sale_payment_sheet_menu.xml @@ -0,0 +1,70 @@ + + + + + sale.payment.sheet.account.invoice.tree + account.move + + + + + + + + + + + + + + + + + + + Invoices + account.move + tree,form + + [ + ('state', '=', 'posted'), + ('type', 'in', ['out_invoice', 'out_refund'])] + { + 'default_type':'out_invoice', + 'type':'out_invoice', + 'journal_type': 'sale', + 'search_default_in_payment': True, + 'search_default_unpaid': True, + } + + + + + diff --git a/sale_payment_sheet/views/sale_payment_sheet_views.xml b/sale_payment_sheet/views/sale_payment_sheet_views.xml new file mode 100644 index 00000000000..310981f4e93 --- /dev/null +++ b/sale_payment_sheet/views/sale_payment_sheet_views.xml @@ -0,0 +1,170 @@ + + + + sale.payment.sheet.tree + sale.payment.sheet + + + + + + + + + + + + + sale.payment.sheet.search + sale.payment.sheet + + + + + + + + + + + + + + + + + sale.payment.sheet.form + sale.payment.sheet + 1 + +
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + + + + Sale payment sheet + sale.payment.sheet + tree,form + [] + {} + + +

+ Register a invoice payment (Salesman) +

+
+
+ + diff --git a/sale_payment_sheet/wizards/__init__.py b/sale_payment_sheet/wizards/__init__.py new file mode 100644 index 00000000000..b2756b3b8e6 --- /dev/null +++ b/sale_payment_sheet/wizards/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import sale_invoice_payment diff --git a/sale_payment_sheet/wizards/sale_invoice_payment.py b/sale_payment_sheet/wizards/sale_invoice_payment.py new file mode 100644 index 00000000000..4349bba8325 --- /dev/null +++ b/sale_payment_sheet/wizards/sale_invoice_payment.py @@ -0,0 +1,95 @@ +# Copyright 2020 Tecnativa - Carlos Dauden +# Copyright 2020 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class SaleInvoicePaymentWiz(models.TransientModel): + _name = "sale.invoice.payment.wiz" + _description = "Sale invoice payment wizard" + + user_id = fields.Many2one( + "res.users", + string="Responsible", + required=False, + default=lambda self: self.env.user, + ) + commercial_journal_ids = fields.Many2many(related="user_id.commercial_journal_ids") + currency_id = fields.Many2one( + "res.currency", compute="_compute_currency", string="Currency" + ) + journal_id = fields.Many2one( + comodel_name="account.journal", string="Journal", required=True, + ) + amount = fields.Monetary( + currency_field="currency_id", string="Amount", required=True, + ) + + @api.model + def default_get(self, fields_list): + res = super(SaleInvoicePaymentWiz, self).default_get(fields_list) + invoices = self.env["account.move"].browse(self.env.context.get("active_ids")) + res["amount"] = sum(invoices.mapped("amount_residual")) + return res + + @api.depends("journal_id") + def _compute_currency(self): + for wiz in self: + wiz.currency_id = wiz.journal_id.currency_id + + def create_sale_invoice_payment_sheet(self): + invoices = ( + self.env["account.move"] + .browse(self.env.context.get("active_ids")) + .filtered( + lambda inv: inv.state == "posted" + and inv.invoice_payment_state != "paid" + ) + ) + if not invoices: + return + # Search an open payment sheet or create one if not exists + SalePaymentSheet = self.env["sale.payment.sheet"] + sheet = SalePaymentSheet.search( + [ + ("state", "=", "open"), + ("user_id", "=", self.env.user.id), + ("journal_id", "=", self.journal_id.id), + ("date", "=", fields.Date.today()), + ] + ) + if not sheet: + sheet = SalePaymentSheet.create( + { + "user_id": self.env.user.id, + "journal_id": self.journal_id.id, + "date": fields.Date.today(), + } + ) + for invoice in invoices: + if not self.amount: + break + sheet_line = sheet.line_ids.filtered(lambda ln: ln.invoice_id == invoice) + amount_pay = ( + invoice.amount_residual + if self.amount >= invoice.amount_residual + else self.amount + ) + # TODO: What to do if a line has been finded + if sheet_line: + sheet_line.amount = amount_pay + else: + sheet.line_ids = [ + ( + 0, + 0, + { + "amount": amount_pay, + "partner_id": invoice.partner_id.id, + "invoice_id": invoice.id, + }, + ) + ] + self.amount -= amount_pay + return sheet diff --git a/sale_payment_sheet/wizards/sale_invoice_payment_view.xml b/sale_payment_sheet/wizards/sale_invoice_payment_view.xml new file mode 100644 index 00000000000..0df6c7f089e --- /dev/null +++ b/sale_payment_sheet/wizards/sale_invoice_payment_view.xml @@ -0,0 +1,38 @@ + + + + Sale invoice payment wizard + sale.invoice.payment.wiz + +
+ + + + + + +
+
+
+
+
+ +
From 03113ad0e18f44b11a1521a52cc467a6e6aca059 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Wed, 24 Feb 2021 22:19:42 +0100 Subject: [PATCH 02/20] [ADD] sale_payment_sheet: Allow add refund invoices to payment sheets --- .../tests/test_sale_payment_sheet.py | 3 +- .../wizards/sale_invoice_payment.py | 42 ++++++++++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/sale_payment_sheet/tests/test_sale_payment_sheet.py b/sale_payment_sheet/tests/test_sale_payment_sheet.py index 77b990b6417..71cbf35a9ff 100644 --- a/sale_payment_sheet/tests/test_sale_payment_sheet.py +++ b/sale_payment_sheet/tests/test_sale_payment_sheet.py @@ -49,7 +49,8 @@ def test_payment_wizard(self): wiz_form.journal_id = self.bank_journal wiz_form.amount = 150.00 wiz = wiz_form.save() - sheet = wiz.create_sale_invoice_payment_sheet() + action = wiz.create_sale_invoice_payment_sheet() + sheet = self.SalePaymentSheet.browse(action["res_id"]) self.assertEqual(len(sheet.line_ids), 2) line_partial_payment = sheet.line_ids.filtered( lambda ln: ln.transaction_type == "partial" diff --git a/sale_payment_sheet/wizards/sale_invoice_payment.py b/sale_payment_sheet/wizards/sale_invoice_payment.py index 4349bba8325..6038c6b31e3 100644 --- a/sale_payment_sheet/wizards/sale_invoice_payment.py +++ b/sale_payment_sheet/wizards/sale_invoice_payment.py @@ -30,7 +30,13 @@ class SaleInvoicePaymentWiz(models.TransientModel): def default_get(self, fields_list): res = super(SaleInvoicePaymentWiz, self).default_get(fields_list) invoices = self.env["account.move"].browse(self.env.context.get("active_ids")) - res["amount"] = sum(invoices.mapped("amount_residual")) + res["journal_id"] = self.env.user.commercial_journal_ids[:1].id + res["amount"] = 0.0 + for invoice in invoices: + if invoice.type == "out_refund": + res["amount"] -= invoice.amount_residual + else: + res["amount"] += invoice.amount_residual return res @api.depends("journal_id") @@ -67,16 +73,33 @@ def create_sale_invoice_payment_sheet(self): "date": fields.Date.today(), } ) - for invoice in invoices: - if not self.amount: - break - sheet_line = sheet.line_ids.filtered(lambda ln: ln.invoice_id == invoice) + # First process refund invoices su summarize negative amounts + for invoice in invoices.filtered(lambda inv: inv.type == "out_refund"): + self._process_invoice(sheet, invoice) + + for invoice in invoices.filtered(lambda inv: inv.type == "out_invoice").sorted( + key=lambda x: (x.date, x.id) + ): + self._process_invoice(sheet, invoice) + return sheet.get_formview_action() + + def _process_invoice(self, sheet, invoice): + sheet_line = sheet.line_ids.filtered(lambda ln: ln.invoice_id == invoice) + invoice_amount_residual = ( + invoice.amount_residual + if invoice.type == "out_invoice" + else -invoice.amount_residual + ) + amount_pay = 0.0 + if self.amount > 0: amount_pay = ( - invoice.amount_residual - if self.amount >= invoice.amount_residual + invoice_amount_residual + if self.amount >= invoice_amount_residual else self.amount ) - # TODO: What to do if a line has been finded + elif invoice.type == "out_refund": + amount_pay = invoice_amount_residual + if amount_pay: if sheet_line: sheet_line.amount = amount_pay else: @@ -91,5 +114,4 @@ def create_sale_invoice_payment_sheet(self): }, ) ] - self.amount -= amount_pay - return sheet + self.amount -= amount_pay From 3a8aec0aed1f365aa83d1751f56b0136d0818e83 Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Tue, 27 Apr 2021 20:02:43 +0200 Subject: [PATCH 03/20] [ADD] sale_payment_sheet: Add total amount in tree view TT29429 --- sale_payment_sheet/i18n/es.po | 5 +++-- sale_payment_sheet/i18n/sale_payment_sheet.pot | 5 +++-- sale_payment_sheet/models/sale_payment_sheet.py | 15 ++++++++++++++- .../tests/test_sale_payment_sheet.py | 1 + .../views/sale_payment_sheet_views.xml | 1 + 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sale_payment_sheet/i18n/es.po b/sale_payment_sheet/i18n/es.po index 49475286ea6..a87a3bbba2c 100644 --- a/sale_payment_sheet/i18n/es.po +++ b/sale_payment_sheet/i18n/es.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 13.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-09 08:37+0000\n" -"PO-Revision-Date: 2021-02-09 09:39+0100\n" +"POT-Creation-Date: 2021-04-27 17:57+0000\n" +"PO-Revision-Date: 2021-04-27 19:57+0200\n" "Last-Translator: Sergio Teruel \n" "Language-Team: \n" "Language: es\n" @@ -456,6 +456,7 @@ msgid "The amount of a cash transaction cannot be 0." msgstr "El importe de una transacción en efectivo no puede ser 0." #. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__amount_total #: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree #: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form msgid "Total" diff --git a/sale_payment_sheet/i18n/sale_payment_sheet.pot b/sale_payment_sheet/i18n/sale_payment_sheet.pot index a8a5776f85b..99fb5304593 100644 --- a/sale_payment_sheet/i18n/sale_payment_sheet.pot +++ b/sale_payment_sheet/i18n/sale_payment_sheet.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 13.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-02-09 08:37+0000\n" -"PO-Revision-Date: 2021-02-09 08:37+0000\n" +"POT-Creation-Date: 2021-04-27 17:57+0000\n" +"PO-Revision-Date: 2021-04-27 17:57+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -453,6 +453,7 @@ msgid "The amount of a cash transaction cannot be 0." msgstr "" #. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__amount_total #: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree #: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form msgid "Total" diff --git a/sale_payment_sheet/models/sale_payment_sheet.py b/sale_payment_sheet/models/sale_payment_sheet.py index f2888aa2a71..b5b4165da7d 100644 --- a/sale_payment_sheet/models/sale_payment_sheet.py +++ b/sale_payment_sheet/models/sale_payment_sheet.py @@ -78,6 +78,17 @@ class SalePaymentSheet(models.Model): statement_id = fields.Many2one( comodel_name="account.bank.statement", string="Bank statement" ) + amount_total = fields.Monetary( + string="Total", store=True, readonly=True, compute="_compute_amount_total" + ) + + @api.depends("line_ids.amount") + def _compute_amount_total(self): + """ Summarize total amount lines, this field already is signed + depending on invoice type. + """ + for sheet in self: + sheet.amount_total = sum(sheet.line_ids.mapped("amount")) @api.model def _default_journal(self): @@ -171,7 +182,9 @@ class SalePaymentSheetLine(models.Model): ) date = fields.Date( required=True, - default=lambda self: self._context.get("date", fields.Date.context_today(self)), + default=lambda self: self.env.context.get( + "date", fields.Date.context_today(self) + ), ) sheet_id = fields.Many2one( "sale.payment.sheet", diff --git a/sale_payment_sheet/tests/test_sale_payment_sheet.py b/sale_payment_sheet/tests/test_sale_payment_sheet.py index 71cbf35a9ff..1402cbeee28 100644 --- a/sale_payment_sheet/tests/test_sale_payment_sheet.py +++ b/sale_payment_sheet/tests/test_sale_payment_sheet.py @@ -62,6 +62,7 @@ def test_payment_wizard(self): ) self.assertTrue(line_full_payment) self.assertEqual(line_full_payment.invoice_id, self.invoice1) + self.assertEqual(sheet.amount_total, 150.00) def _create_payment_sheet(self): with Form(self.SalePaymentSheet) as sheet_form: diff --git a/sale_payment_sheet/views/sale_payment_sheet_views.xml b/sale_payment_sheet/views/sale_payment_sheet_views.xml index 310981f4e93..d216005abf0 100644 --- a/sale_payment_sheet/views/sale_payment_sheet_views.xml +++ b/sale_payment_sheet/views/sale_payment_sheet_views.xml @@ -8,6 +8,7 @@ + From 143716b64a6373d4e2bc4f86340df97158c86e2a Mon Sep 17 00:00:00 2001 From: sergio-teruel Date: Wed, 5 May 2021 16:03:17 +0200 Subject: [PATCH 04/20] [IMP] sale_payment_sheet: Allow to group statement lines by reference TT29569 --- sale_payment_sheet/i18n/es.po | 14 ++++-- .../i18n/sale_payment_sheet.pot | 11 ++++- .../models/sale_payment_sheet.py | 48 ++++++++++++++----- .../views/sale_payment_sheet_views.xml | 1 + .../wizards/sale_invoice_payment.py | 7 ++- .../wizards/sale_invoice_payment_view.xml | 1 + 6 files changed, 62 insertions(+), 20 deletions(-) diff --git a/sale_payment_sheet/i18n/es.po b/sale_payment_sheet/i18n/es.po index a87a3bbba2c..35e5f94c73f 100644 --- a/sale_payment_sheet/i18n/es.po +++ b/sale_payment_sheet/i18n/es.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 13.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-27 17:57+0000\n" -"PO-Revision-Date: 2021-04-27 19:57+0200\n" +"POT-Creation-Date: 2021-05-05 13:54+0000\n" +"PO-Revision-Date: 2021-05-05 15:58+0200\n" "Last-Translator: Sergio Teruel \n" "Language-Team: \n" "Language: es\n" @@ -186,6 +186,11 @@ msgstr "" msgid "Group By" msgstr "Agrupado por..." +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__group_lines +msgid "Group statement lines by" +msgstr "Agrupar Líneas del extracto bancario por" + #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__id #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__id @@ -347,8 +352,10 @@ msgid "Payments" msgstr "Pagos" #. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__ref #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__name #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__ref +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__group_lines__ref msgid "Reference" msgstr "Referencia" @@ -547,6 +554,3 @@ msgstr "Resumen de pagos de facturas" #: model:ir.actions.report,name:sale_payment_sheet.action_report_sale_payment_sheet msgid "sale payment sheet summary" msgstr "Resumen de pagos de facturas" - -#~ msgid "Journal Entries" -#~ msgstr "Asientos contables" diff --git a/sale_payment_sheet/i18n/sale_payment_sheet.pot b/sale_payment_sheet/i18n/sale_payment_sheet.pot index 99fb5304593..f9f1874a0d1 100644 --- a/sale_payment_sheet/i18n/sale_payment_sheet.pot +++ b/sale_payment_sheet/i18n/sale_payment_sheet.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 13.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-27 17:57+0000\n" -"PO-Revision-Date: 2021-04-27 17:57+0000\n" +"POT-Creation-Date: 2021-05-05 13:54+0000\n" +"PO-Revision-Date: 2021-05-05 13:54+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -183,6 +183,11 @@ msgstr "" msgid "Group By" msgstr "" +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__group_lines +msgid "Group statement lines by" +msgstr "" + #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__id #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__id @@ -344,8 +349,10 @@ msgid "Payments" msgstr "" #. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__ref #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__name #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__ref +#: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__group_lines__ref msgid "Reference" msgstr "" diff --git a/sale_payment_sheet/models/sale_payment_sheet.py b/sale_payment_sheet/models/sale_payment_sheet.py index b5b4165da7d..181c4a0231c 100644 --- a/sale_payment_sheet/models/sale_payment_sheet.py +++ b/sale_payment_sheet/models/sale_payment_sheet.py @@ -81,6 +81,9 @@ class SalePaymentSheet(models.Model): amount_total = fields.Monetary( string="Total", store=True, readonly=True, compute="_compute_amount_total" ) + group_lines = fields.Selection( + selection=[("ref", "Reference")], string="Group statement lines by" + ) @api.depends("line_ids.amount") def _compute_amount_total(self): @@ -118,6 +121,13 @@ def unlink(self): ) return super().unlink() + @api.model + def _statement_line_key(self, line): + if self.group_lines == "ref": + return (line.partner_id.id, line.ref) + else: + return (line.id,) + def button_confirm_sheet(self): sheets = self.filtered(lambda r: r.state == "open") BankStatement = self.env["account.bank.statement"].sudo() @@ -131,23 +141,37 @@ def button_confirm_sheet(self): "user_id": sheet.user_id.id, } ) + vals_dic = {} for line in sheet.line_ids: - vals = { - "name": line.name, - "date": line.date, - "amount": line.amount, - "partner_id": line.partner_id.id, - "ref": line.ref, - "note": line.note, - "sequence": line.sequence, - "statement_id": statement.id, - } + key = self._statement_line_key(line) + if line.invoice_id.type == "out_refund" and line.amount > 0.0: # convert to negative amounts if user pays a refund out # invoice with a positive amount. - vals["amount"] = -line.amount + amount_line = -line.amount + else: + amount_line = line.amount + + if key not in vals_dic: + vals_dic[key] = { + "name": line.name, + "date": line.date, + "amount": amount_line, + "partner_id": line.partner_id.id, + "ref": line.ref, + "note": line.note, + "sequence": line.sequence, + "statement_id": statement.id, + "payment_sheet_line_ids": line, + } + else: + vals_dic[key]["amount"] += amount_line + vals_dic[key]["name"] += " {}".format(line.invoice_id.name) + vals_dic[key]["payment_sheet_line_ids"] += line + for vals in vals_dic.values(): + payment_sheet_line_ids = vals.pop("payment_sheet_line_ids", None) statement_line = BankStatementLine.create(vals) - line.statement_line_id = statement_line + payment_sheet_line_ids.statement_line_id = statement_line sheet.message_post( body=_("Sheet %s confirmed, bank statement were created.") % (statement.name,) diff --git a/sale_payment_sheet/views/sale_payment_sheet_views.xml b/sale_payment_sheet/views/sale_payment_sheet_views.xml index d216005abf0..8b8d007afa8 100644 --- a/sale_payment_sheet/views/sale_payment_sheet_views.xml +++ b/sale_payment_sheet/views/sale_payment_sheet_views.xml @@ -105,6 +105,7 @@ options="{'no_create': True}" groups="base.group_multi_company" /> + diff --git a/sale_payment_sheet/wizards/sale_invoice_payment.py b/sale_payment_sheet/wizards/sale_invoice_payment.py index 6038c6b31e3..ceb380e1273 100644 --- a/sale_payment_sheet/wizards/sale_invoice_payment.py +++ b/sale_payment_sheet/wizards/sale_invoice_payment.py @@ -25,6 +25,7 @@ class SaleInvoicePaymentWiz(models.TransientModel): amount = fields.Monetary( currency_field="currency_id", string="Amount", required=True, ) + ref = fields.Char(string="Reference") @api.model def default_get(self, fields_list): @@ -84,12 +85,15 @@ def create_sale_invoice_payment_sheet(self): return sheet.get_formview_action() def _process_invoice(self, sheet, invoice): - sheet_line = sheet.line_ids.filtered(lambda ln: ln.invoice_id == invoice) + all_sheet_lines = sheet.line_ids.filtered(lambda ln: ln.invoice_id == invoice) + sheet_line = all_sheet_lines.filtered(lambda ln: ln.ref == self.ref) + other_lines = all_sheet_lines - sheet_line invoice_amount_residual = ( invoice.amount_residual if invoice.type == "out_invoice" else -invoice.amount_residual ) + invoice_amount_residual -= sum(other_lines.mapped("amount")) amount_pay = 0.0 if self.amount > 0: amount_pay = ( @@ -111,6 +115,7 @@ def _process_invoice(self, sheet, invoice): "amount": amount_pay, "partner_id": invoice.partner_id.id, "invoice_id": invoice.id, + "ref": self.ref, }, ) ] diff --git a/sale_payment_sheet/wizards/sale_invoice_payment_view.xml b/sale_payment_sheet/wizards/sale_invoice_payment_view.xml index 0df6c7f089e..6d1fb372556 100644 --- a/sale_payment_sheet/wizards/sale_invoice_payment_view.xml +++ b/sale_payment_sheet/wizards/sale_invoice_payment_view.xml @@ -14,6 +14,7 @@ domain="[('id', 'in', commercial_journal_ids)]" /> +
diff --git a/sale_payment_sheet/tests/test_sale_payment_sheet.py b/sale_payment_sheet/tests/test_sale_payment_sheet.py index 1402cbeee28..f3115beff34 100644 --- a/sale_payment_sheet/tests/test_sale_payment_sheet.py +++ b/sale_payment_sheet/tests/test_sale_payment_sheet.py @@ -2,15 +2,19 @@ # Copyright 2020 Tecnativa - Sergio Teruel # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields -from odoo.exceptions import UserError +from freezegun import freeze_time + +from odoo.exceptions import UserError, ValidationError from odoo.tests import Form, SavepointCase +@freeze_time("2021-01-01 09:30:00") class TestSaleInvoicePayment(SavepointCase): @classmethod def setUpClass(cls): super().setUpClass() + # Remove time zone from user to avoid to time local representation + cls.env.user.partner_id.tz = False cls.wizard_obj = cls.env["sale.invoice.payment.wiz"] cls.SalePaymentSheet = cls.env["sale.payment.sheet"] cls.partner = cls.env["res.partner"].create({"name": "Test partner"}) @@ -101,9 +105,7 @@ def test_manual_payment_sheet(self): self.assertEqual( line_partial_payment.name, "[{}] - {} - {} - ({})".format( - fields.Datetime.context_timestamp( - line_partial_payment, line_partial_payment.create_date - ).strftime("%H:%M"), + "09:30", line_partial_payment.sheet_id.user_id.name, line_partial_payment.invoice_id.name, dict( @@ -137,3 +139,13 @@ def test_payment_sheet_line_unlink(self): sheet.button_confirm_sheet() with self.assertRaises(UserError): sheet.line_ids.unlink() + + def test_payment_sheet_invoice_constraint(self): + # You can not add full invoice payed more than one time. + sheet = self._create_payment_sheet() + with self.assertRaises(ValidationError): + with Form(sheet) as sheet_form: + with sheet_form.line_ids.new() as line_sheet: + line_sheet.partner_id = self.partner + line_sheet.invoice_id = self.invoice1 + sheet_form.save() From 677df207e5f8816a936620526146389b3f822237 Mon Sep 17 00:00:00 2001 From: Cesar Andres Sanchez Date: Mon, 6 Jun 2022 22:43:57 +0200 Subject: [PATCH 06/20] [IMP] sale_payment_sheet: black, isort, prettier --- sale_payment_sheet/models/res_users.py | 3 ++- sale_payment_sheet/models/sale_payment_sheet.py | 2 +- sale_payment_sheet/tests/test_sale_payment_sheet.py | 3 ++- sale_payment_sheet/wizards/sale_invoice_payment.py | 8 ++++++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/sale_payment_sheet/models/res_users.py b/sale_payment_sheet/models/res_users.py index dc7e5a3798c..e7c83b6f940 100644 --- a/sale_payment_sheet/models/res_users.py +++ b/sale_payment_sheet/models/res_users.py @@ -9,5 +9,6 @@ class ResUsers(models.Model): _inherit = "res.users" commercial_journal_ids = fields.Many2many( - comodel_name="account.journal", string="Allowed journals for commercial", + comodel_name="account.journal", + string="Allowed journals for commercial", ) diff --git a/sale_payment_sheet/models/sale_payment_sheet.py b/sale_payment_sheet/models/sale_payment_sheet.py index 24814fd7a60..a9894245b78 100644 --- a/sale_payment_sheet/models/sale_payment_sheet.py +++ b/sale_payment_sheet/models/sale_payment_sheet.py @@ -87,7 +87,7 @@ class SalePaymentSheet(models.Model): @api.depends("line_ids.amount") def _compute_amount_total(self): - """ Summarize total amount lines, this field already is signed + """Summarize total amount lines, this field already is signed depending on invoice type. """ for sheet in self: diff --git a/sale_payment_sheet/tests/test_sale_payment_sheet.py b/sale_payment_sheet/tests/test_sale_payment_sheet.py index f3115beff34..6c621f5266c 100644 --- a/sale_payment_sheet/tests/test_sale_payment_sheet.py +++ b/sale_payment_sheet/tests/test_sale_payment_sheet.py @@ -47,7 +47,8 @@ def _create_invoice(self): def test_payment_wizard(self): PaymentWiz = self.env["sale.invoice.payment.wiz"].with_context( - active_model="account.move", active_ids=(self.invoice1 + self.invoice2).ids, + active_model="account.move", + active_ids=(self.invoice1 + self.invoice2).ids, ) with Form(PaymentWiz) as wiz_form: wiz_form.journal_id = self.bank_journal diff --git a/sale_payment_sheet/wizards/sale_invoice_payment.py b/sale_payment_sheet/wizards/sale_invoice_payment.py index ceb380e1273..2227214c718 100644 --- a/sale_payment_sheet/wizards/sale_invoice_payment.py +++ b/sale_payment_sheet/wizards/sale_invoice_payment.py @@ -20,10 +20,14 @@ class SaleInvoicePaymentWiz(models.TransientModel): "res.currency", compute="_compute_currency", string="Currency" ) journal_id = fields.Many2one( - comodel_name="account.journal", string="Journal", required=True, + comodel_name="account.journal", + string="Journal", + required=True, ) amount = fields.Monetary( - currency_field="currency_id", string="Amount", required=True, + currency_field="currency_id", + string="Amount", + required=True, ) ref = fields.Char(string="Reference") From 5f08fbf95b246de9f425a58b32b03409c0c4de7a Mon Sep 17 00:00:00 2001 From: Cesar Andres Sanchez Date: Mon, 6 Jun 2022 22:48:54 +0200 Subject: [PATCH 07/20] [MIG] sale_payment_sheet: Migration to 15.0 --- sale_payment_sheet/README.rst | 11 ++- sale_payment_sheet/__manifest__.py | 2 +- sale_payment_sheet/i18n/es.po | 75 ++++++++----------- .../i18n/sale_payment_sheet.pot | 30 +++----- .../models/sale_payment_sheet.py | 33 ++++---- sale_payment_sheet/readme/CONTRIBUTORS.rst | 5 +- sale_payment_sheet/readme/DESCRIPTION.rst | 5 +- .../tests/test_sale_payment_sheet.py | 7 +- .../views/sale_payment_sheet_menu.xml | 1 - .../views/sale_payment_sheet_views.xml | 5 +- .../wizards/sale_invoice_payment.py | 20 ++--- 11 files changed, 92 insertions(+), 102 deletions(-) diff --git a/sale_payment_sheet/README.rst b/sale_payment_sheet/README.rst index 5178ffa99cc..f5d968c643a 100644 --- a/sale_payment_sheet/README.rst +++ b/sale_payment_sheet/README.rst @@ -23,10 +23,13 @@ Sale payment sheet :target: https://runbot.odoo-community.org/runbot/167/13.0 :alt: Try me on Runbot -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| -This module allows to commercial users register payments in a payment sheet. -This payment sheet will generate a bank statement when is confirmed. +This module allows salesmen to register payments in a new document called payment sheet, accessible only with the sales permission. + +This sheet includes the paid amount, and an optional reference to which invoice(s) is(are) being paid. + +This payment sheet will generate a bank statement when confirmed. **Table of contents** @@ -112,7 +115,7 @@ promote its widespread use. Current `maintainer `__: -|maintainer-sergio-teruel| +|maintainer-sergio-teruel| This module is part of the `OCA/sale-workflow `_ project on GitHub. diff --git a/sale_payment_sheet/__manifest__.py b/sale_payment_sheet/__manifest__.py index dc449330ede..a9d69468d8f 100644 --- a/sale_payment_sheet/__manifest__.py +++ b/sale_payment_sheet/__manifest__.py @@ -5,7 +5,7 @@ "name": "Sale payment sheet", "summary": "Allow to create invoice payments to commercial users without " "accounting permissions", - "version": "13.0.1.0.0", + "version": "15.0.1.0.0", "development_status": "Beta", "category": "Account", "website": "https://github.com/OCA/sale-workflow", diff --git a/sale_payment_sheet/i18n/es.po b/sale_payment_sheet/i18n/es.po index 394e4e7b416..dae110b2618 100644 --- a/sale_payment_sheet/i18n/es.po +++ b/sale_payment_sheet/i18n/es.po @@ -1,21 +1,22 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: +# * sale_order_type +# +# This file contains the translation of the following modules: # * sale_payment_sheet # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-15 23:38+0000\n" -"PO-Revision-Date: 2021-07-16 01:40+0200\n" -"Last-Translator: Sergio Teruel \n" +"POT-Creation-Date: 2022-06-28 20:48+0000\n" +"PO-Revision-Date: 2022-06-28 20:48+0000\n" +"Last-Translator: César A. Sánchez\n" "Language-Team: \n" -"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 2.3\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" #. module: sale_payment_sheet #: model:ir.actions.report,print_report_name:sale_payment_sheet.action_report_sale_payment_sheet @@ -149,21 +150,11 @@ msgstr "Borrador" msgid "External Reference" msgstr "Referencia Externa" -#. module: sale_payment_sheet -#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__failed_message_ids -msgid "Failed Messages" -msgstr "Mensajes Fallidos" - #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_follower_ids msgid "Followers" msgstr "Seguidores" -#. module: sale_payment_sheet -#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_channel_ids -msgid "Followers (Channels)" -msgstr "Seguidores (Canales)" - #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_partner_ids msgid "Followers (Partners)" @@ -176,7 +167,8 @@ msgstr "Completo" #. module: sale_payment_sheet #: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet_line__sequence -msgid "Gives the sequence order when displaying a list of payment sheet lines." +msgid "" +"Gives the sequence order when displaying a list of payment sheet lines." msgstr "" "Indica el orden de secuencia cuando se muestra una lista de líneas de la " "hoja de pagos." @@ -191,6 +183,11 @@ msgstr "Agrupado por..." msgid "Group statement lines by" msgstr "Agrupar Líneas del extracto bancario por" +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__has_message +msgid "Has Message" +msgstr "Tiene mensaje" + #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__id #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__id @@ -206,6 +203,7 @@ msgstr "Si está marcado, hay nuevos mensajes que requieren su atención." #. module: sale_payment_sheet #: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_has_error +#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_has_sms_error msgid "If checked, some messages have a delivery error." msgstr "Si se encuentra marcado, algunos mensajes tienen error de envío." @@ -218,7 +216,6 @@ msgstr "Factura" #. module: sale_payment_sheet #: model:ir.actions.act_window,name:sale_payment_sheet.action_invoice_sale_payment_sheet #: model:ir.ui.menu,name:sale_payment_sheet.sale_payment_invoice -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree msgid "Invoices" msgstr "Facturas" @@ -270,25 +267,15 @@ msgstr "Última actualización en" msgid "Main Attachment" msgstr "Adjuntos principales" -#. module: sale_payment_sheet -#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_content -msgid "Message Content" -msgstr "Contenido del mensaje" - #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_has_error msgid "Message Delivery error" msgstr "Error de Envío de Mensaje" -#. module: sale_payment_sheet -#: model:ir.model.fields,help:sale_payment_sheet.field_sale_payment_sheet__message_content -msgid "Message content, to be used only in searches" -msgstr "Contenido del mensaje, para usarse en búsquedas" - #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_ids msgid "Messages" -msgstr "Messages" +msgstr "Mensajes" #. module: sale_payment_sheet #: model:ir.model.fields.selection,name:sale_payment_sheet.selection__sale_payment_sheet__state__open @@ -375,6 +362,11 @@ msgstr "Reestablecer a Nuevo" msgid "Responsible" msgstr "Responsable" +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_has_sms_error +msgid "SMS Delivery error" +msgstr "Error en la entrega del SMS" + #. module: sale_payment_sheet #: model:ir.model,name:sale_payment_sheet.model_sale_payment_sheet msgid "Sale Payment Sheet" @@ -396,14 +388,8 @@ msgstr "Pago de facturas" msgid "Sale invoice payment wizard" msgstr "Asistente de pago de factura" -#. module: sale_payment_sheet -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_tree -msgid "Sale invoice payments" -msgstr "Pagos de facturas" - #. module: sale_payment_sheet #: model:ir.actions.act_window,name:sale_payment_sheet.action_sale_payment_sheet -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form msgid "Sale payment sheet" msgstr "Hoja de pagos" @@ -435,7 +421,6 @@ msgstr "Hoja %s confirmada, se crearon los extractos bancarios." #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__line_ids -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form msgid "Sheet lines" msgstr "Líneas" @@ -466,14 +451,16 @@ msgstr "El importe de una transacción en efectivo no puede ser 0." #: code:addons/sale_payment_sheet/models/sale_payment_sheet.py:0 #, python-format msgid "" -"This invoice already has been included in other payment sheet or the amount " -"payed is greather than residual invoice amount.\n" -" Invoice: %s Amount payed: %s" +"This invoice already has been included in other payment sheet or the amount payed is greather than residual invoice amount.\n" +" Invoice: %(invoice_name)s\n" +" Amount payed: %(amount_payed)s\n" +" Payment sheets: %(payment_lines_name)s" msgstr "" "Esta factura ya se ha incluido en otra hoja de pagos o el importe pagado es " "mayor al importe pendiente de la factura.\n" -" Factura: %s Importe pagado: %s" - +" Factura: %(invoice_name)s\n" +" Importe pagado: %(amount_payed)s\n" +" Hojas de pago: %(payment_lines_name)s" #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__amount_total #: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree @@ -488,7 +475,7 @@ msgstr "Importe total" #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__transaction_type -msgid "Transaction type" +msgid "Transaction Type" msgstr "Tipo de transacción" #. module: sale_payment_sheet diff --git a/sale_payment_sheet/i18n/sale_payment_sheet.pot b/sale_payment_sheet/i18n/sale_payment_sheet.pot index 4a513abed13..a21344eacce 100644 --- a/sale_payment_sheet/i18n/sale_payment_sheet.pot +++ b/sale_payment_sheet/i18n/sale_payment_sheet.pot @@ -4,8 +4,10 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-06-28 20:47+0000\n" +"PO-Revision-Date: 2022-06-28 20:47+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -150,11 +152,6 @@ msgstr "" msgid "Followers" msgstr "" -#. module: sale_payment_sheet -#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_channel_ids -msgid "Followers (Channels)" -msgstr "" - #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__message_partner_ids msgid "Followers (Partners)" @@ -181,6 +178,11 @@ msgstr "" msgid "Group statement lines by" msgstr "" +#. module: sale_payment_sheet +#: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__has_message +msgid "Has Message" +msgstr "" + #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_invoice_payment_wiz__id #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__id @@ -209,7 +211,6 @@ msgstr "" #. module: sale_payment_sheet #: model:ir.actions.act_window,name:sale_payment_sheet.action_invoice_sale_payment_sheet #: model:ir.ui.menu,name:sale_payment_sheet.sale_payment_invoice -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_invoice_tree msgid "Invoices" msgstr "" @@ -382,14 +383,8 @@ msgstr "" msgid "Sale invoice payment wizard" msgstr "" -#. module: sale_payment_sheet -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_tree -msgid "Sale invoice payments" -msgstr "" - #. module: sale_payment_sheet #: model:ir.actions.act_window,name:sale_payment_sheet.action_sale_payment_sheet -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form msgid "Sale payment sheet" msgstr "" @@ -421,7 +416,6 @@ msgstr "" #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet__line_ids -#: model_terms:ir.ui.view,arch_db:sale_payment_sheet.view_sale_payment_sheet_form msgid "Sheet lines" msgstr "" @@ -453,9 +447,9 @@ msgstr "" #, python-format msgid "" "This invoice already has been included in other payment sheet or the amount payed is greather than residual invoice amount.\n" -" Invoice: %s\n" -" Amount payed: %s\n" -" Payment sheets: %s" +" Invoice: %(invoice_name)s\n" +" Amount payed:%(amount_payed)s\n" +" Payment sheets: %(payment_lines_name)s" msgstr "" #. module: sale_payment_sheet @@ -472,7 +466,7 @@ msgstr "" #. module: sale_payment_sheet #: model:ir.model.fields,field_description:sale_payment_sheet.field_sale_payment_sheet_line__transaction_type -msgid "Transaction type" +msgid "Transaction Type" msgstr "" #. module: sale_payment_sheet diff --git a/sale_payment_sheet/models/sale_payment_sheet.py b/sale_payment_sheet/models/sale_payment_sheet.py index a9894245b78..baf25201f09 100644 --- a/sale_payment_sheet/models/sale_payment_sheet.py +++ b/sale_payment_sheet/models/sale_payment_sheet.py @@ -145,7 +145,7 @@ def button_confirm_sheet(self): for line in sheet.line_ids: key = self._statement_line_key(line) - if line.invoice_id.type == "out_refund" and line.amount > 0.0: + if line.invoice_id.move_type == "out_refund" and line.amount > 0.0: # convert to negative amounts if user pays a refund out # invoice with a positive amount. amount_line = -line.amount @@ -158,8 +158,7 @@ def button_confirm_sheet(self): "date": line.date, "amount": amount_line, "partner_id": line.partner_id.id, - "ref": line.ref, - "note": line.note, + "payment_ref": line.ref, "sequence": line.sequence, "statement_id": statement.id, "payment_sheet_line_ids": line, @@ -181,10 +180,11 @@ def button_confirm_sheet(self): def button_reopen(self): self.ensure_one() self_sudo = self.sudo() - if self_sudo.statement_id.line_ids.filtered("journal_entry_ids"): + if self_sudo.statement_id.line_ids.filtered("is_reconciled"): raise UserError( _("You can not reopen a sheet that has any reconciled line.") ) + self_sudo.statement_id.button_reopen() self_sudo.statement_id.unlink() self.state = "open" @@ -256,14 +256,15 @@ class SalePaymentSheetLine(models.Model): transaction_type = fields.Selection( [("partial", "Partial payment"), ("full", "Full payment")], compute="_compute_transaction_type", - string="Transaction type", ) @api.depends("amount", "invoice_id") def _compute_transaction_type(self): for line in self: amount = ( - line.amount if line.invoice_id.type == "out_invoice" else -line.amount + line.amount + if line.invoice_id.move_type == "out_invoice" + else -line.amount ) if float_compare( amount, @@ -294,11 +295,13 @@ def _compute_name(self): def _compute_amount(self): for line in self: amount = line.invoice_id.amount_residual - line.amount = amount if line.invoice_id.type == "out_invoice" else -amount + line.amount = ( + amount if line.invoice_id.move_type == "out_invoice" else -amount + ) def _inverse_amount(self): for line in self: - if line.invoice_id.type == "out_refund" and line.amount > 0.0: + if line.invoice_id.move_type == "out_refund" and line.amount > 0.0: line.amount = -line.amount @api.constrains("invoice_id", "amount") @@ -329,13 +332,15 @@ def _check_invoice(self): _( "This invoice already has been included in other payment sheet" " or the amount payed is greather than residual invoice amount." - "\n Invoice: %s\n Amount payed: %s\n Payment sheets: %s" - % ( - line.invoice_id.name, - amount_payed, - payment_lines.mapped("sheet_id.name"), - ) + "\n Invoice: %(invoice_name)s\n Amount payed: " + "%(amount_payed)s\n Payment sheets:" + " %(payment_lines_name)s" ) + % { + "invoice_name": line.invoice_id.name, + "amount_payed": amount_payed, + "payment_lines_name": payment_lines.mapped("sheet_id.name"), + } ) def unlink(self): diff --git a/sale_payment_sheet/readme/CONTRIBUTORS.rst b/sale_payment_sheet/readme/CONTRIBUTORS.rst index 29ec7c3c9da..de3f5c32e0d 100644 --- a/sale_payment_sheet/readme/CONTRIBUTORS.rst +++ b/sale_payment_sheet/readme/CONTRIBUTORS.rst @@ -1,4 +1,5 @@ * `Tecnativa `__: - * Carlos Dauden - * Sergio Teruel + * Carlos Dauden + * Sergio Teruel + * César A. Sánchez diff --git a/sale_payment_sheet/readme/DESCRIPTION.rst b/sale_payment_sheet/readme/DESCRIPTION.rst index bd730118c39..ae5e74be178 100644 --- a/sale_payment_sheet/readme/DESCRIPTION.rst +++ b/sale_payment_sheet/readme/DESCRIPTION.rst @@ -1,2 +1,3 @@ -This module allows to commercial users register payments in a payment sheet. -This payment sheet will generate a bank statement when is confirmed. +This module allows salesmen to register payments in a new document called payment sheet, accessible only with the sales permission. +This sheet includes the paid amount, and an optional reference to which invoice(s) is(are) being paid. +This payment sheet will generate a bank statement when confirmed. diff --git a/sale_payment_sheet/tests/test_sale_payment_sheet.py b/sale_payment_sheet/tests/test_sale_payment_sheet.py index 6c621f5266c..e25970dd552 100644 --- a/sale_payment_sheet/tests/test_sale_payment_sheet.py +++ b/sale_payment_sheet/tests/test_sale_payment_sheet.py @@ -35,7 +35,7 @@ def setUpClass(cls): def _create_invoice(self): with Form( - self.env["account.move"].with_context(default_type="out_invoice") + self.env["account.move"].with_context(default_move_type="out_invoice") ) as invoice_form: invoice_form.partner_id = self.partner with invoice_form.invoice_line_ids.new() as line_form: @@ -76,6 +76,7 @@ def _create_payment_sheet(self): with sheet_form.line_ids.new() as line_sheet: line_sheet.partner_id = self.partner line_sheet.invoice_id = invoice + line_sheet.ref = "REF{}".format(line_sheet.id) # Only write for partial amount payed, by default the # amount line is total amount residual if index > 0: @@ -141,6 +142,10 @@ def test_payment_sheet_line_unlink(self): with self.assertRaises(UserError): sheet.line_ids.unlink() + def test_button_bank_statement(self): + sheet = self._create_payment_sheet() + sheet.button_bank_statement() + def test_payment_sheet_invoice_constraint(self): # You can not add full invoice payed more than one time. sheet = self._create_payment_sheet() diff --git a/sale_payment_sheet/views/sale_payment_sheet_menu.xml b/sale_payment_sheet/views/sale_payment_sheet_menu.xml index 0fd2d2a8151..f86373c7e6c 100644 --- a/sale_payment_sheet/views/sale_payment_sheet_menu.xml +++ b/sale_payment_sheet/views/sale_payment_sheet_menu.xml @@ -9,7 +9,6 @@ account.move diff --git a/sale_payment_sheet/views/sale_payment_sheet_views.xml b/sale_payment_sheet/views/sale_payment_sheet_views.xml index 8b8d007afa8..ecd7fe301dc 100644 --- a/sale_payment_sheet/views/sale_payment_sheet_views.xml +++ b/sale_payment_sheet/views/sale_payment_sheet_views.xml @@ -4,7 +4,7 @@ sale.payment.sheet.tree sale.payment.sheet - + @@ -50,7 +50,7 @@ sale.payment.sheet 1 -
+