diff --git a/hr_expense_invoice/README.rst b/hr_expense_invoice/README.rst new file mode 100644 index 000000000..a745db1dd --- /dev/null +++ b/hr_expense_invoice/README.rst @@ -0,0 +1,124 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================================ +Supplier invoices on HR expenses +================================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:7e8117b1a98ba5b52b401bb69a1bca1aef01b7721082c76adc1f8954109bf825 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fhr--expense-lightgray.png?logo=github + :target: https://github.com/OCA/hr-expense/tree/19.0/hr_expense_invoice + :alt: OCA/hr-expense +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-expense-19-0/hr-expense-19-0-hr_expense_invoice + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/hr-expense&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module should be used when a supplier invoice is paid by an +employee. It allows to set a supplier invoice for each expense line, +adding the corresponding journal items to transfer the debt to the +employee. + +There are 2 ways to reference expense to invoice. + +1. On expense, directly select one invoice. +2. On expense report, use button "Create Vendor Bill" to create one + invoice for multiple expenses. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +**Reference one invoice to an expense** + +- Create an expense sheet. +- Add an expense line to sheet with an invoice_id selected or create one + new. +- Process expense sheet. +- On paying expense sheet, you are reconciling supplier invoice too. + +**Create one invoice to multiple expenses** + +- Create an expense sheet with one or multiple expense lines +- After approved, click button "Create Vendor Bill" +- Select multiple expense to create an invoice, and process it. +- New invoice will be create and link to the selected expense lines. +- Validate newly create invoice. +- On paying expense sheet, you are reconciling supplier invoice(s) too. + +Known issues / Roadmap +====================== + +- Multiple payment terms for a supplier invoice are not handled + correctly. +- Partial reconcile supplier invoices are also not correctly handled. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Pedro M. Baeza + - Vicent Cubells + - Víctor Martínez + +- Kitti Upariphutthiphong +- Rattapong Chokmasermkul +- Saran Lim. + +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/hr-expense `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_expense_invoice/__init__.py b/hr_expense_invoice/__init__.py new file mode 100644 index 000000000..69f7babdf --- /dev/null +++ b/hr_expense_invoice/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/hr_expense_invoice/__manifest__.py b/hr_expense_invoice/__manifest__.py new file mode 100644 index 000000000..035d81599 --- /dev/null +++ b/hr_expense_invoice/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2015-2021 Tecnativa - Pedro M. Baeza +# Copyright 2017 Tecnativa - Vicent Cubells +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Supplier invoices on HR expenses", + "version": "19.0.1.0.0", + "category": "Human Resources", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/hr-expense", + "depends": ["hr_expense"], + "data": [ + "views/account_move_views.xml", + "views/hr_expense_views.xml", + "data/mail_message_subtype.xml", + ], + "installable": True, +} diff --git a/hr_expense_invoice/data/mail_message_subtype.xml b/hr_expense_invoice/data/mail_message_subtype.xml new file mode 100644 index 000000000..15e25256f --- /dev/null +++ b/hr_expense_invoice/data/mail_message_subtype.xml @@ -0,0 +1,9 @@ + + + + Approved + hr.expense.sheet + + Expense report approved + + diff --git a/hr_expense_invoice/i18n/cs_CZ.po b/hr_expense_invoice/i18n/cs_CZ.po new file mode 100644 index 000000000..17f9e98ed --- /dev/null +++ b/hr_expense_invoice/i18n/cs_CZ.po @@ -0,0 +1,129 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +# Translators: +# Lukáš Spurný , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-23 03:45+0000\n" +"PO-Revision-Date: 2018-02-23 03:45+0000\n" +"Last-Translator: Lukáš Spurný , 2018\n" +"Language-Team: Czech (Czech Republic) (https://www.transifex.com/oca/" +"teams/23907/cs_CZ/)\n" +"Language: cs_CZ\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Výdaje" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Zpráva o výdajích" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +#, fuzzy +msgid "Expenses" +msgstr "Výdaje" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +#, fuzzy +msgid "Invoice Count" +msgstr "Faktura" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, fuzzy, python-format +msgid "Invoices" +msgstr "Faktura" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" diff --git a/hr_expense_invoice/i18n/de.po b/hr_expense_invoice/i18n/de.po new file mode 100644 index 000000000..93e1e9ff0 --- /dev/null +++ b/hr_expense_invoice/i18n/de.po @@ -0,0 +1,127 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-07-12 14:43+0000\n" +"Last-Translator: Maria Sparenberg \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.7.1\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, fuzzy +msgid "Create Vendor Bill" +msgstr "Lieferantenrechnung" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Spesen" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Spesen-Bericht" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +#, fuzzy +msgid "Expenses" +msgstr "Spesen" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +#, fuzzy +msgid "Invoice Count" +msgstr "Rechnung" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, fuzzy, python-format +msgid "Invoices" +msgstr "Rechnung" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "Lieferantenrechnung" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" diff --git a/hr_expense_invoice/i18n/es.po b/hr_expense_invoice/i18n/es.po new file mode 100644 index 000000000..c51105990 --- /dev/null +++ b/hr_expense_invoice/i18n/es.po @@ -0,0 +1,140 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-09-27 16:34+0000\n" +"PO-Revision-Date: 2023-10-29 23:38+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "Crear Factura de Vendedor" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Gasto" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Informe de gastos" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +msgid "Expenses" +msgstr "Gastos" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +msgid "Invoice Count" +msgstr "Conteo de Factura" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, python-format +msgid "Invoices" +msgstr "Facturas" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "Entrada Diaria" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "Estado de la hoja" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "Factura de Proveedor" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" +"El importe de la factura del proveedor no coincide.\n" +"Asegúrese de que el importe de la factura del proveedor coincide con el " +"importe de sus líneas de gasto" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "Debe publicarse el estado de la factura del proveedor" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" +"No puede modificar el importe total, ya que hay un gasto vinculado a esta " +"factura." + +#~ msgid "Expense Report State" +#~ msgstr "Estado del Informe de Gastos" + +#~ msgid "Register Payment" +#~ msgstr "Registrar Pago" + +#, python-format +#~ msgid "Register payment on expense's invoice is not allowed" +#~ msgstr "No se permite registrar el pago en la factura del gasto" diff --git a/hr_expense_invoice/i18n/fr.po b/hr_expense_invoice/i18n/fr.po new file mode 100644 index 000000000..5b2061c64 --- /dev/null +++ b/hr_expense_invoice/i18n/fr.po @@ -0,0 +1,129 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +# Translators: +# guillaume bauer , 2017 +# Alexandre Fayolle , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-23 03:45+0000\n" +"PO-Revision-Date: 2018-02-23 03:45+0000\n" +"Last-Translator: Alexandre Fayolle , 2018\n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Note de frais" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Rapport de dépenses" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +#, fuzzy +msgid "Expenses" +msgstr "Note de frais" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +#, fuzzy +msgid "Invoice Count" +msgstr "Facture" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, fuzzy, python-format +msgid "Invoices" +msgstr "Facture" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" diff --git a/hr_expense_invoice/i18n/hr.po b/hr_expense_invoice/i18n/hr.po new file mode 100644 index 000000000..408f0ddb2 --- /dev/null +++ b/hr_expense_invoice/i18n/hr.po @@ -0,0 +1,129 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +# Translators: +# Bole , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-23 03:45+0000\n" +"PO-Revision-Date: 2018-02-23 03:45+0000\n" +"Last-Translator: Bole , 2017\n" +"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Trošak" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Izvještaj troškova" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +#, fuzzy +msgid "Expenses" +msgstr "Trošak" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +#, fuzzy +msgid "Invoice Count" +msgstr "Račun" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, fuzzy, python-format +msgid "Invoices" +msgstr "Račun" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" diff --git a/hr_expense_invoice/i18n/hr_expense_invoice.pot b/hr_expense_invoice/i18n/hr_expense_invoice.pot new file mode 100644 index 000000000..17ac05504 --- /dev/null +++ b/hr_expense_invoice/i18n/hr_expense_invoice.pot @@ -0,0 +1,176 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "" +"\n" +" Expense\n" +" " +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__amount_residual +msgid "Amount Due" +msgstr "" + +#. module: hr_expense_invoice +#: model:mail.message.subtype,name:hr_expense_invoice.mt_expense_approved_inherited +msgid "Approved" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "" + +#. module: hr_expense_invoice +#: model:mail.message.subtype,description:hr_expense_invoice.mt_expense_approved_inherited +msgid "Expense report approved" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +msgid "Expenses" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +msgid "Invoice Count" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Invoices" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"Please specify an expense journal in order to generate" +" accounting entries." +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"Please specify if the expenses for this report were paid by" +" the company, or the employee" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "Show missing work email employees" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"The work email of some employees is missing. Please add it on" +" the employee form" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "You can only generate an accounting entry for approved expense(s)." +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"You cannot create accounting entries for an expense " +"report without expenses." +msgstr "" diff --git a/hr_expense_invoice/i18n/it.po b/hr_expense_invoice/i18n/it.po new file mode 100644 index 000000000..1743086ee --- /dev/null +++ b/hr_expense_invoice/i18n/it.po @@ -0,0 +1,141 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-05-30 13:38+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "Spesa" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "Crea una fattura fornitore" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Spesa" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Nota spese" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +msgid "Expenses" +msgstr "Spese" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +msgid "Invoice Count" +msgstr "Numero fatture" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, python-format +msgid "Invoices" +msgstr "Fatture" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "Registrazione contabile" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "Movimento contabile" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" +"Riferimento alla spesa con una fattura collegata che ha generato questa " +"registrazione contabile del trasferimento" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "Stato prospetto" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "Fattura spesa origine" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "Movimento di trasferimento" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "Fattura fornitore" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" +"Differenza fattura fornitore!\n" +"Assicurarsi che il valore nel conto del fornitore sia pari al valore delle " +"righe di spesa" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "Lo stato del conto fornitore deve essere Inviato" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" +"Non si può cambiare il valore totale, perché c'è una spesa collegata a " +"questa fattura." + +#~ msgid "Expense Report State" +#~ msgstr "Stato nota spese" + +#~ msgid "Register Payment" +#~ msgstr "Registra pagamento" + +#, python-format +#~ msgid "Register payment on expense's invoice is not allowed" +#~ msgstr "Non è consentito registrare il pagamento sulla fattura delle spese" diff --git a/hr_expense_invoice/i18n/nl_NL.po b/hr_expense_invoice/i18n/nl_NL.po new file mode 100644 index 000000000..d82751219 --- /dev/null +++ b/hr_expense_invoice/i18n/nl_NL.po @@ -0,0 +1,128 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +# Translators: +# Peter Hageman , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-11-28 01:43+0000\n" +"PO-Revision-Date: 2017-11-28 01:43+0000\n" +"Last-Translator: Peter Hageman , 2017\n" +"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/" +"teams/23907/nl_NL/)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Onkostennota" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +#, fuzzy +msgid "Expenses" +msgstr "Onkostennota" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +msgid "Invoice Count" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, python-format +msgid "Invoices" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" diff --git a/hr_expense_invoice/i18n/pt.po b/hr_expense_invoice/i18n/pt.po new file mode 100644 index 000000000..41c6049de --- /dev/null +++ b/hr_expense_invoice/i18n/pt.po @@ -0,0 +1,126 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-10-10 12:08+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.1.1\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "Despesa" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "Relatório de Despesas" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__expense_ids +#, fuzzy +msgid "Expenses" +msgstr "Despesa" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +#, fuzzy +msgid "Invoice Count" +msgstr "Fatura" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +#, fuzzy, python-format +msgid "Invoices" +msgstr "Fatura" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_payment__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#, python-format +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +#, python-format +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" diff --git a/hr_expense_invoice/i18n/tr.po b/hr_expense_invoice/i18n/tr.po new file mode 100644 index 000000000..b29cfb948 --- /dev/null +++ b/hr_expense_invoice/i18n/tr.po @@ -0,0 +1,177 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_expense_invoice +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.view_move_form +msgid "" +"\n" +" Expense\n" +" " +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__amount_residual +msgid "Amount Due" +msgstr "" + +#. module: hr_expense_invoice +#: model:mail.message.subtype,name:hr_expense_invoice.mt_expense_approved_inherited +msgid "Approved" +msgstr "" + +#. module: hr_expense_invoice +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Create Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense +msgid "Expense" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_hr_expense_sheet +msgid "Expense Report" +msgstr "" + +#. module: hr_expense_invoice +#: model:mail.message.subtype,description:hr_expense_invoice.mt_expense_approved_inherited +msgid "Expense report approved" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__expense_ids +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__expense_ids +msgid "Expenses" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense_sheet__invoice_count +msgid "Invoice Count" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +#: model_terms:ir.ui.view,arch_db:hr_expense_invoice.hr_expense_sheet_form_view_inherit_sale_expense +msgid "Invoices" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move +msgid "Journal Entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model,name:hr_expense_invoice.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"Please specify an expense journal in order to generate" +" accounting entries." +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"Please specify if the expenses for this report were paid by" +" the company, or the employee" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,help:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,help:hr_expense_invoice.field_account_move__source_invoice_expense_id +msgid "" +"Reference to the expense with a linked invoice that generated thistransfer " +"journal entry" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__sheet_id_state +msgid "Sheet state" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "Show missing work email employees" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_bank_statement_line__source_invoice_expense_id +#: model:ir.model.fields,field_description:hr_expense_invoice.field_account_move__source_invoice_expense_id +msgid "Source Invoice Expense" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"The work email of some employees is missing. Please add it on" +" the employee form" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__transfer_move_ids +msgid "Transfer Move" +msgstr "" + +#. module: hr_expense_invoice +#: model:ir.model.fields,field_description:hr_expense_invoice.field_hr_expense__invoice_id +msgid "Vendor Bill" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"Vendor bill amount mismatch!\n" +"Please make sure amount in vendor bills equal to amount of its expense lines" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense.py:0 +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "Vendor bill state must be Posted" +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "You can only generate an accounting entry for approved expense(s)." +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/account_move.py:0 +msgid "" +"You can't change the total amount, as there's an expense linked to this " +"invoice." +msgstr "" + +#. module: hr_expense_invoice +#. odoo-python +#: code:addons/hr_expense_invoice/models/hr_expense_sheet.py:0 +msgid "" +"You cannot create accounting entries for an expense " +"report without expenses." +msgstr "" diff --git a/hr_expense_invoice/models/__init__.py b/hr_expense_invoice/models/__init__.py new file mode 100644 index 000000000..d869298ab --- /dev/null +++ b/hr_expense_invoice/models/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import hr_expense +from . import hr_expense_sheet +from . import account_move diff --git a/hr_expense_invoice/models/account_move.py b/hr_expense_invoice/models/account_move.py new file mode 100644 index 000000000..e2f5846b4 --- /dev/null +++ b/hr_expense_invoice/models/account_move.py @@ -0,0 +1,76 @@ +# Copyright 2019 Ecosoft +# Copyright 2021 Tecnativa - Víctor Martínez +# Copyright 2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools import float_compare + + +class AccountMove(models.Model): + _inherit = "account.move" + + expense_ids = fields.One2many( + comodel_name="hr.expense", inverse_name="invoice_id", string="Expenses" + ) + source_invoice_expense_id = fields.Many2one( + comodel_name="hr.expense", + help="Reference to the expense with a linked invoice that generated this" + "transfer journal entry", + ) + + @api.constrains("amount_total") + def _check_expense_ids(self): + DecimalPrecision = self.env["decimal.precision"] + precision = DecimalPrecision.precision_get("Product Price") + for move in self.filtered("expense_ids"): + expense_amount = sum(move.expense_ids.mapped("total_amount_currency")) + if float_compare(expense_amount, move.amount_total, precision) != 0: + raise ValidationError( + self.env._( + "You can't change the total amount, as there's an expense " + "linked to this invoice." + ) + ) + + def action_view_expense(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "view_mode": "form", + "res_model": "hr.expense", + "res_id": self.expense_ids[:1].id, + } + + def action_force_register_payment(self): + if not self.source_invoice_expense_id: + return super().action_force_register_payment() + else: + return self.line_ids.action_register_payment() + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + @api.constrains("account_id", "display_type") + def _check_payable_receivable(self): + _self = self.filtered("expense_id") + return super(AccountMoveLine, (self - _self))._check_payable_receivable() + + def reconcile(self): + """Mark expenses paid by employee having invoice when reconciling them.""" + expenses = self.move_id.source_invoice_expense_id + not_paid_expenses = expenses.filtered(lambda x: x.state != "done") + res = super().reconcile() + not_paid_expense_sheets = not_paid_expenses.sheet_id.filtered( + lambda x: x.state != "done" + ) + paid_expenses = not_paid_expenses.filtered( + lambda expense: expense.currency_id.is_zero(expense.amount_residual) + ) + paid_expenses.write({"state": "done"}) + paid_sheets = not_paid_expense_sheets.filtered( + lambda x: all(expense.state == "done" for expense in x.expense_line_ids) + ) + paid_sheets.set_to_paid() + return res diff --git a/hr_expense_invoice/models/hr_expense.py b/hr_expense_invoice/models/hr_expense.py new file mode 100644 index 000000000..3dde9b98e --- /dev/null +++ b/hr_expense_invoice/models/hr_expense.py @@ -0,0 +1,188 @@ +# Copyright 2017 Tecnativa - Vicent Cubells +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2021 Tecnativa - Víctor Martínez +# Copyright 2015-2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import Command, api, fields, models +from odoo.exceptions import UserError + + +class HrExpense(models.Model): + _inherit = "hr.expense" + + sheet_id_state = fields.Selection(related="sheet_id.state", string="Sheet state") + invoice_id = fields.Many2one( + comodel_name="account.move", + string="Vendor Bill", + domain=[ + ("move_type", "=", "in_invoice"), + ("state", "=", "posted"), + ("payment_state", "=", "not_paid"), + ("expense_ids", "=", False), + ], + copy=False, + ) + transfer_move_ids = fields.One2many( + comodel_name="account.move", + inverse_name="source_invoice_expense_id", + ) + # This field has been added to reintroduce tracking for the amount due on each + # expense, a feature that existed in previous versions. The tracking is necessary + # to accurately reflect the payment state of the expense sheet. + amount_residual = fields.Monetary( + string="Amount Due", compute="_compute_amount_residual", store=True + ) + + def _prepare_invoice_values(self): + invoice_lines = [ + Command.create( + { + "product_id": self.product_id.id, + "name": self.name, + # Odoo considers always the amount taxes included, we need to take + # the base amount and quantity = 1 + "price_unit": self.untaxed_amount_currency, + "quantity": 1, + "account_id": self.account_id.id, + "analytic_distribution": self.analytic_distribution, + "tax_ids": [Command.set(self.tax_ids.ids)], + } + ) + ] + return { + "name": "/", + "move_type": "in_invoice", + "invoice_date": self.date, + "invoice_line_ids": invoice_lines, + } + + def _prepare_own_account_transfer_move_vals(self): + self.ensure_one() + self = self.with_company(self.company_id) + # TODO: Allow to select a specific journal + journal = self.env["account.journal"].search( + [ + ("company_id", "=", self.company_id.id), + ("type", "=", "general"), + ], + limit=1, + ) + employee_partner = self.employee_id.sudo().work_contact_id + invoice_partner = self.invoice_id.partner_id + ap_lines = self.invoice_id.line_ids.filtered( + lambda x: x.display_type == "payment_term" + ) + amount_invoice = sum(ap_lines.mapped("credit")) + return { + "journal_id": journal.id, + "move_type": "entry", + "name": "/", + "date": self.date, + "ref": self.name, + "source_invoice_expense_id": self.id, + "expense_sheet_id": self.sheet_id.id, + "line_ids": [ + Command.create( + { + "account_id": ap_lines.account_id[:1].id, + "partner_id": invoice_partner.id, + "debit": amount_invoice, + } + ), + Command.create( + { + "account_id": employee_partner.property_account_payable_id.id, + "partner_id": employee_partner.id, + "credit": amount_invoice, + } + ), + ], + } + + def action_expense_create_invoice(self): + invoice = self.env["account.move"].create(self._prepare_invoice_values()) + attachments = self.env["ir.attachment"].search( + [("res_model", "=", self._name), ("res_id", "in", self.ids)] + ) + for attachment in attachments: + attachment.copy({"res_model": invoice._name, "res_id": invoice.id}) + self.write( + { + "invoice_id": invoice.id, + "quantity": 1, + "tax_ids": False, + "price_unit": invoice.amount_total, + } + ) + return True + + @api.constrains("invoice_id") + def _check_invoice_id(self): + for expense in self: # Only non binding expense + if ( + not expense.sheet_id + and expense.invoice_id + and expense.invoice_id.state != "posted" + ): + raise UserError(self.env._("Vendor bill state must be Posted")) + + @api.onchange("invoice_id") + def _onchange_invoice_id(self): + """Assure quantity is 1 if an invoice is set for having proper totals, and + the rest of the fields that are not computed writable, avoiding to ud + """ + if self.invoice_id: + self.quantity = 1 + self.name = self.name.split(" | ")[0].strip() + self.name = "{} | {}".format(self.name or "", self.invoice_id.name) + self.date = self.invoice_id.date + if self.invoice_id.company_id != self.company_id: + # for avoiding to trigger dependent computes + self.company_id = self.invoice_id.company_id.id + + # tax_ids put as dependency for assuring this is computed after setting tax_ids + @api.depends("invoice_id", "tax_ids") + def _compute_price_unit(self): + with_invoice = self.filtered("invoice_id") + for record in with_invoice: + record.price_unit = record.invoice_id.amount_total + return super(HrExpense, self - with_invoice)._compute_price_unit() + + # tax_ids put as dependency for assuring this is computed after setting tax_ids + @api.depends("invoice_id", "tax_ids") + def _compute_total_amount_currency(self): + with_invoice = self.filtered("invoice_id") + for record in with_invoice: + record.total_amount_currency = record.invoice_id.amount_total + return super(HrExpense, self - with_invoice)._compute_total_amount_currency() + + @api.depends("invoice_id") + def _compute_currency_id(self): + with_invoice = self.filtered("invoice_id") + for record in with_invoice: + record.currency_id = record.invoice_id.currency_id.id + return super(HrExpense, self - with_invoice)._compute_currency_id() + + @api.depends("invoice_id") + def _compute_tax_ids(self): + with_invoice = self.filtered("invoice_id") + for record in with_invoice: + record.tax_ids = [(5,)] + return super(HrExpense, self - with_invoice)._compute_tax_ids() + + @api.depends( + "transfer_move_ids.line_ids.amount_residual", + "transfer_move_ids.line_ids.amount_residual_currency", + ) + def _compute_amount_residual(self): + """Compute the amount residual for expenses paid by employee with invoices.""" + for rec in self: + if not rec.currency_id or rec.currency_id == rec.company_currency_id: + residual_field = "amount_residual" + else: + residual_field = "amount_residual_currency" + payment_term_lines = rec.transfer_move_ids.sudo().line_ids.filtered( + lambda x: x.account_type in ("asset_receivable", "liability_payable") + ) + rec.amount_residual = -sum(payment_term_lines.mapped(residual_field)) diff --git a/hr_expense_invoice/models/hr_expense_sheet.py b/hr_expense_invoice/models/hr_expense_sheet.py new file mode 100644 index 000000000..b615f0432 --- /dev/null +++ b/hr_expense_invoice/models/hr_expense_sheet.py @@ -0,0 +1,266 @@ +# Copyright 2017 Tecnativa - Vicent Cubells +# Copyright 2015-2024 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import Command, api, fields, models +from odoo.exceptions import RedirectWarning, UserError +from odoo.tools import config, float_compare + + +class HrExpenseSheet(models.Model): + _inherit = "hr.expense.sheet" + + invoice_count = fields.Integer(compute="_compute_invoice_count") + + def get_expense_sheets_with_invoices(self, func): + return self.filtered( + lambda sheet: func(expense.invoice_id for expense in sheet.expense_line_ids) + ) + + def _do_create_ap_moves(self): + # Create AP transfer entry for expenses paid by employees + for expense in self.expense_line_ids.filtered("invoice_id"): + if expense.payment_mode == "own_account": + move_vals = expense._prepare_own_account_transfer_move_vals() + move = self.env["account.move"].create(move_vals) + move.action_post() + # reconcile with the invoice + ap_lines = expense.invoice_id.line_ids.filtered( + lambda x: x.display_type == "payment_term" + ) + transfer_line = move.line_ids.filtered( + lambda x, partner=expense.invoice_id.partner_id: x.partner_id + == partner + ) + (ap_lines + transfer_line).reconcile() + + def action_sheet_move_post(self): + # Handle expense sheets with invoices + sheets_all_inovices = self.get_expense_sheets_with_invoices(all) + res = super(HrExpenseSheet, self - sheets_all_inovices).action_sheet_move_post() + # Use 'any' here because there may be mixed sheets + # and we have to create ap moves for those invoices + for expense in self.get_expense_sheets_with_invoices(any): + expense._validate_expense_invoice() + expense._check_can_create_move() + expense._do_create_ap_moves() + # The payment state is set in a fixed way in super, but it depends on the + # payment state of the invoices when there are some of them linked + expense.filtered( + lambda x: x.expense_line_ids.invoice_id + and x.payment_mode == "company_account" + )._compute_from_account_move_ids() + return res + + def set_to_paid(self): + """Don't mark sheet as paid when reconciling invoices.""" + if self.env.context.get("use_hr_expense_invoice"): + return True + return super().set_to_paid() + + def _compute_invoice_count(self): + Invoice = self.env["account.move"] + can_read = Invoice.has_access("read") + for sheet in self: + sheet.invoice_count = ( + can_read and len(sheet.expense_line_ids.mapped("invoice_id")) or 0 + ) + + @api.depends( + "expense_line_ids.invoice_id.payment_state", + "expense_line_ids.amount_residual", + ) + def _compute_from_account_move_ids(self): + """Determine the payment status for lines with expense invoices linked""" + invoice_sheets = self.filtered(lambda x: x.expense_line_ids.invoice_id) + invoice_sheets.payment_state = "not_paid" + for sheet in invoice_sheets: + lines = sheet.expense_line_ids + lines_with_invoices = len(lines.filtered("invoice_id")) + if sheet.payment_mode == "company_account": + lines_with_paid_invoices = len( + lines.filtered(lambda x: x.invoice_id.payment_state == "paid") + ) + lines_with_partial_invoices = len( + lines.filtered(lambda x: x.invoice_id.payment_state == "partial") + ) + else: + lines_with_paid_invoices = len( + lines.filtered( + lambda x: x.transfer_move_ids and x.amount_residual == 0 + ) + ) + lines_with_partial_invoices = 0 # TODO: Consider partial reconciliation + if lines_with_invoices == lines_with_paid_invoices: + sheet.payment_state = "paid" + elif lines_with_paid_invoices or lines_with_partial_invoices: + sheet.payment_state = "partial" + return super( + HrExpenseSheet, self - invoice_sheets + )._compute_from_account_move_ids() + + def _prepare_bills_vals(self): + res = super()._prepare_bills_vals() + test_condition = not config["test_enable"] or self.env.context.get( + "test_hr_expense_invoice" + ) + if test_condition: + expenses_without_invoice = self.expense_line_ids.filtered( + lambda r: not r.invoice_id + ) + if expenses_without_invoice: + res["line_ids"] = [ + Command.create(expense._prepare_move_lines_vals()) + for expense in expenses_without_invoice + ] + + return res + + def _validate_expense_invoice(self): + """Check several criteria that needs to be met for creating the move.""" + expense_lines = self.mapped("expense_line_ids").filtered("invoice_id") + DecimalPrecision = self.env["decimal.precision"] + precision = DecimalPrecision.precision_get("Product Price") + invoices = expense_lines.mapped("invoice_id") + if not invoices: + return + # All invoices must confirmed + if any(invoices.filtered(lambda i: i.state != "posted")): + raise UserError(self.env._("Vendor bill state must be Posted")) + expense_amount = sum(expense_lines.mapped("total_amount_currency")) + invoice_amount = sum(invoices.mapped("amount_total")) + # Expense amount must equal invoice amount + if float_compare(expense_amount, invoice_amount, precision) != 0: + raise UserError( + self.env._( + "Vendor bill amount mismatch!\nPlease make sure amount in " + "vendor bills equal to amount of its expense lines" + ) + ) + + def action_view_invoices(self): + self.ensure_one() + action = { + "name": self.env._("Invoices"), + "type": "ir.actions.act_window", + "res_model": "account.move", + "target": "current", + } + invoice_ids = self.expense_line_ids.mapped("invoice_id").ids + view = self.env.ref("account.view_move_form") + if len(invoice_ids) == 1: + invoice = invoice_ids[0] + action["res_id"] = invoice + action["view_mode"] = "form" + action["views"] = [(view.id, "form")] + else: + action["view_mode"] = "list,form" + action["domain"] = [("id", "in", invoice_ids)] + return action + + @api.depends() + def _compute_state(self): + """Set proper state according to linked invoices.""" + sheets_with_invoices = self.filtered( + lambda sheet: all( + expense.invoice_id and expense.invoice_id.state == "posted" + for expense in sheet.expense_line_ids + ) + and sheet.state == sheet.approval_state + ) + company_account_sheets = sheets_with_invoices.filtered( + lambda sheet: sheet.payment_mode == "company_account" + ) + company_account_sheets.state = "done" + sheets_with_paid_invoices = ( + sheets_with_invoices - company_account_sheets + ).filtered( + lambda sheet: all( + expense.invoice_id.payment_state != "not_paid" + for expense in sheet.expense_line_ids + ) + ) + sheets_with_paid_invoices.state = "post" + return super(HrExpenseSheet, self - sheets_with_invoices)._compute_state() + + def _do_approve(self): + expense_sheets_with_invoices = self.get_expense_sheets_with_invoices(all) + own_account_sheets = self.filtered( + lambda sheet: sheet.payment_mode == "own_account" + ) + sheets_to_bypass = expense_sheets_with_invoices + own_account_sheets + res = super(HrExpenseSheet, self - sheets_to_bypass)._do_approve() + for sheet in sheets_to_bypass.filtered( + lambda s: s.state in {"submit", "draft"} + ): + sheet.write( + { + "approval_state": "approve", + "user_id": sheet.user_id.id or self.env.user.id, + "approval_date": fields.Date.context_today(sheet), + } + ) + self.activity_update() + return res + + def _track_subtype(self, init_values): + self.ensure_one() + if self.state == "approve": + return self.env.ref("hr_expense_invoice.mt_expense_approved_inherited") + else: + super()._track_subtype(init_values) + + def _check_can_create_move(self): + expense_sheets_with_invoices = self.get_expense_sheets_with_invoices(any) + res = super( + HrExpenseSheet, self - expense_sheets_with_invoices + )._check_can_create_move() + # We copy this method because the expenses are in 'approve' or 'posted' + # in case this is the second run, instead of 'submit' + if any(not sheet.expense_line_ids for sheet in expense_sheets_with_invoices): + raise UserError( + self.env._( + "You cannot create accounting entries for an expense \ + report without expenses." + ) + ) + if any( + sheet.state not in ["approve", "post"] + for sheet in expense_sheets_with_invoices + ): + raise UserError( + self.env._( + "You can only generate an accounting entry for approved expense(s)." + ) + ) + if any(not sheet.journal_id for sheet in expense_sheets_with_invoices): + raise UserError( + self.env._( + "Please specify an expense journal in order to generate \ + accounting entries." + ) + ) + if False in expense_sheets_with_invoices.mapped("payment_mode"): + raise UserError( + self.env._( + "Please specify if the expenses for this report were paid by \ + the company, or the employee" + ) + ) + missing_email_employees = expense_sheets_with_invoices.filtered( + lambda sheet: not sheet.employee_id.work_email + ).employee_id + if missing_email_employees: + action = expense_sheets_with_invoices.env["ir.actions.actions"]._for_xml_id( + "hr.open_view_employee_list_my" + ) + action["domain"] = [("id", "in", missing_email_employees.ids)] + raise RedirectWarning( + self.env._( + "The work email of some employees is missing. Please add it on \ + the employee form" + ), + action, + self.env._("Show missing work email employees"), + ) + return res diff --git a/hr_expense_invoice/pyproject.toml b/hr_expense_invoice/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/hr_expense_invoice/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_expense_invoice/readme/CONTRIBUTORS.md b/hr_expense_invoice/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..a0ee5e903 --- /dev/null +++ b/hr_expense_invoice/readme/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +- [Tecnativa](https://www.tecnativa.com): + - Pedro M. Baeza + - Vicent Cubells + - Víctor Martínez +- Kitti Upariphutthiphong \<\> +- Rattapong Chokmasermkul \<\> +- Saran Lim. \<\> diff --git a/hr_expense_invoice/readme/DESCRIPTION.md b/hr_expense_invoice/readme/DESCRIPTION.md new file mode 100644 index 000000000..d638be87a --- /dev/null +++ b/hr_expense_invoice/readme/DESCRIPTION.md @@ -0,0 +1,10 @@ +This module should be used when a supplier invoice is paid by an +employee. It allows to set a supplier invoice for each expense line, +adding the corresponding journal items to transfer the debt to the +employee. + +There are 2 ways to reference expense to invoice. + +1. On expense, directly select one invoice. +2. On expense report, use button "Create Vendor Bill" to create one + invoice for multiple expenses. diff --git a/hr_expense_invoice/readme/ROADMAP.md b/hr_expense_invoice/readme/ROADMAP.md new file mode 100644 index 000000000..ceef0a207 --- /dev/null +++ b/hr_expense_invoice/readme/ROADMAP.md @@ -0,0 +1,3 @@ +- Multiple payment terms for a supplier invoice are not handled + correctly. +- Partial reconcile supplier invoices are also not correctly handled. diff --git a/hr_expense_invoice/readme/USAGE.md b/hr_expense_invoice/readme/USAGE.md new file mode 100644 index 000000000..e2fba394e --- /dev/null +++ b/hr_expense_invoice/readme/USAGE.md @@ -0,0 +1,16 @@ +**Reference one invoice to an expense** + +- Create an expense sheet. +- Add an expense line to sheet with an invoice_id selected or create one + new. +- Process expense sheet. +- On paying expense sheet, you are reconciling supplier invoice too. + +**Create one invoice to multiple expenses** + +- Create an expense sheet with one or multiple expense lines +- After approved, click button "Create Vendor Bill" +- Select multiple expense to create an invoice, and process it. +- New invoice will be create and link to the selected expense lines. +- Validate newly create invoice. +- On paying expense sheet, you are reconciling supplier invoice(s) too. diff --git a/hr_expense_invoice/static/description/icon.png b/hr_expense_invoice/static/description/icon.png new file mode 100644 index 000000000..8e5a7f402 Binary files /dev/null and b/hr_expense_invoice/static/description/icon.png differ diff --git a/hr_expense_invoice/static/description/index.html b/hr_expense_invoice/static/description/index.html new file mode 100644 index 000000000..804e2902c --- /dev/null +++ b/hr_expense_invoice/static/description/index.html @@ -0,0 +1,476 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Supplier invoices on HR expenses

+ +

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

+

This module should be used when a supplier invoice is paid by an +employee. It allows to set a supplier invoice for each expense line, +adding the corresponding journal items to transfer the debt to the +employee.

+

There are 2 ways to reference expense to invoice.

+
    +
  1. On expense, directly select one invoice.
  2. +
  3. On expense report, use button “Create Vendor Bill” to create one +invoice for multiple expenses.
  4. +
+

Table of contents

+ +
+

Usage

+

Reference one invoice to an expense

+
    +
  • Create an expense sheet.
  • +
  • Add an expense line to sheet with an invoice_id selected or create one +new.
  • +
  • Process expense sheet.
  • +
  • On paying expense sheet, you are reconciling supplier invoice too.
  • +
+

Create one invoice to multiple expenses

+
    +
  • Create an expense sheet with one or multiple expense lines
  • +
  • After approved, click button “Create Vendor Bill”
  • +
  • Select multiple expense to create an invoice, and process it.
  • +
  • New invoice will be create and link to the selected expense lines.
  • +
  • Validate newly create invoice.
  • +
  • On paying expense sheet, you are reconciling supplier invoice(s) too.
  • +
+
+
+

Known issues / Roadmap

+
    +
  • Multiple payment terms for a supplier invoice are not handled +correctly.
  • +
  • Partial reconcile supplier invoices are also not correctly handled.
  • +
+
+
+

Bug Tracker

+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • 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/hr-expense project on GitHub.

+

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

+
+
+
+
+ + diff --git a/hr_expense_invoice/tests/__init__.py b/hr_expense_invoice/tests/__init__.py new file mode 100644 index 000000000..571c2e78e --- /dev/null +++ b/hr_expense_invoice/tests/__init__.py @@ -0,0 +1 @@ +from . import test_hr_expense_invoice diff --git a/hr_expense_invoice/tests/test_hr_expense_invoice.py b/hr_expense_invoice/tests/test_hr_expense_invoice.py new file mode 100644 index 000000000..977dad44a --- /dev/null +++ b/hr_expense_invoice/tests/test_hr_expense_invoice.py @@ -0,0 +1,291 @@ +# Copyright 2017 Tecnativa - Vicent Cubells +# Copyright 2021 Tecnativa - Pedro M. Baeza +# Copyright 2021-2023 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import base64 + +from odoo import fields +from odoo.exceptions import UserError, ValidationError +from odoo.tests import Form, tagged + +from odoo.addons.hr_expense.tests.common import TestExpenseCommon + + +@tagged("post_install", "-at_install") +class TestHrExpenseInvoice(TestExpenseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, test_hr_expense_invoice=True)) + cls.account_payment_register = cls.env["account.payment.register"] + cls.payment_obj = cls.env["account.payment"] + cls.cash_journal = cls.company_data["default_journal_cash"] + cls.company_data["company"].account_sale_tax_id = False + cls.company_data["company"].account_purchase_tax_id = False + cls.product_a.supplier_taxes_id = False + cls.invoice = cls.init_invoice( + "in_invoice", + products=[cls.product_a], + ) + cls.invoice.invoice_line_ids.price_unit = 100 + cls.invoice2 = cls.invoice.copy( + { + "invoice_date": fields.Date.today(), + } + ) + cls.expense = cls.env["hr.expense"].create( + { + "name": "Expense test", + "employee_id": cls.expense_employee.id, + "product_id": cls.product_a.id, + } + ) + cls._create_attachment(cls, cls.expense._name, cls.expense.id) + cls.expense2 = cls.expense.copy() + cls._create_attachment(cls, cls.expense2._name, cls.expense2.id) + cls.expense3 = cls.expense.copy() + cls._create_attachment(cls, cls.expense3._name, cls.expense3.id) + + def _invoice_register_payment(self, invoice): + res = invoice.action_register_payment() + payment_form = Form(self.env[res["res_model"]].with_context(**res["context"])) + payment_form.journal_id = self.cash_journal + return payment_form.save() + + def _register_payment(self, sheet): + res = sheet.action_register_payment() + register_payment_form = Form( + self.env[res["res_model"]].with_context(**res["context"]) + ) + register_payment_form.journal_id = self.cash_journal + register = register_payment_form.save() + res2 = register.action_create_payments() + payment = self.env[res2["res_model"]].browse(res2["res_id"]) + self.assertEqual(len(payment), 1) + self.assertEqual(sheet.payment_state, "paid") + return payment + + def _create_attachment(self, res_model, res_id): + return self.env["ir.attachment"].create( + { + "name": f"Test attachment {res_id} ({res_model})", + "res_model": res_model, + "res_id": res_id, + "datas": base64.b64encode(b"\xff data"), + } + ) + + def _action_submit_expenses(self, expenses): + expense_sheet = self.env["hr.expense.sheet"].create( + { + "name": "Test expense sheet", + "employee_id": expenses.employee_id.id, + "expense_line_ids": expenses, + } + ) + return expense_sheet + + def test_0_hr_tests_misc(self): + self.assertEqual(self.expense.nb_attachment, 1) + self.assertEqual(self.expense2.nb_attachment, 1) + self.assertEqual(self.expense3.nb_attachment, 1) + + def test_0_hr_test_no_invoice(self): + # We add an expense + sheet = self._action_submit_expenses(self.expense) + self.assertIn(self.expense, sheet.expense_line_ids) + self.assertAlmostEqual( + self.expense.total_amount_currency, self.product_a.standard_price + ) + # We approve sheet, no invoice + sheet.action_submit_sheet() + sheet.action_approve_expense_sheets() + self.assertEqual(sheet.state, "approve") + self.assertFalse(sheet.account_move_ids) + # We post journal entries + sheet.action_sheet_move_post() + self.assertEqual(sheet.state, "post") + self.assertTrue(sheet.account_move_ids) + # We make payment on expense sheet + self._register_payment(sheet) + + def test_1_hr_test_invoice(self): + # We add an expense + self.expense.price_unit = 100 + sheet = self._action_submit_expenses(self.expense) + self.assertIn(self.expense, sheet.expense_line_ids) + # We add invoice to expense + self.invoice.action_post() # residual = 100 + with Form(self.expense) as f: + f.invoice_id = self.invoice + # We approve sheet + sheet.action_approve_expense_sheets() + self.assertEqual(sheet.state, "approve") + self.assertFalse(sheet.account_move_ids) + self.assertEqual(self.invoice.state, "posted") + # Test state not posted + self.invoice.button_draft() + with self.assertRaises(UserError): + sheet.action_sheet_move_post() + self.invoice.action_post() + # We post journal entries + sheet.action_sheet_move_post() + self.assertEqual(sheet.state, "post") + self.assertEqual(self.invoice.payment_state, "paid") + self.assertEqual(sheet.payment_state, "not_paid") + self.assertEqual(self.expense.amount_residual, 100) + self.assertTrue(self.expense.transfer_move_ids) + # Pay the transferred amount (through a hack using reversal) + payment = self._register_payment(sheet) + self.assertEqual(self.expense.amount_residual, 0) + self.assertEqual(sheet.payment_state, "paid") + self.assertEqual(sheet.state, "done") + # Unreconcile the payment + payment.action_draft() + self.assertEqual(self.expense.amount_residual, 100) + self.assertEqual(sheet.payment_state, "not_paid") + + def test_1_hr_test_invoice_paid_by_company(self): + # We add an expense + self.expense.price_unit = 100 + self.expense.payment_mode = "company_account" + sheet = self._action_submit_expenses(self.expense) + self.assertIn(self.expense, sheet.expense_line_ids) + # We add invoice to expense + self.invoice.action_post() # residual = 100.0 + self.expense.invoice_id = self.invoice + # We approve sheet + sheet.action_approve_expense_sheets() + self.assertEqual(sheet.state, "approve") + self.assertFalse(sheet.account_move_ids) + self.assertEqual(self.invoice.state, "posted") + # We post journal entries + sheet.action_sheet_move_post() + self.assertEqual(sheet.state, "done") + self.assertEqual(self.invoice.payment_state, "not_paid") + # Click on View Invoice button link to the correct invoice + res = sheet.action_view_invoices() + self.assertEqual(res["view_mode"], "form") + + def test_2_hr_test_multi_invoices(self): + # We add 2 expenses + self.expense.price_unit = 100 + self.expense2.price_unit = 100 + expenses = self.expense + self.expense2 + sheet = self._action_submit_expenses(expenses) + self.assertIn(self.expense, sheet.expense_line_ids) + self.assertIn(self.expense2, sheet.expense_line_ids) + # We add invoices to expenses + self.invoice.action_post() + self.invoice2.action_post() + self.expense.invoice_id = self.invoice.id + self.expense2.invoice_id = self.invoice2.id + self.assertAlmostEqual(self.expense.total_amount_currency, 100) + self.assertAlmostEqual(self.expense2.total_amount_currency, 100) + # We approve sheet + sheet.action_approve_expense_sheets() + self.assertEqual(sheet.state, "approve") + self.assertFalse(sheet.account_move_ids) + self.assertEqual(self.invoice.state, "posted") + # We post journal entries + sheet.action_sheet_move_post() + self.assertEqual(sheet.state, "post") + self.assertEqual(self.invoice.payment_state, "paid") + self.assertEqual(self.invoice2.payment_state, "paid") + + def test_3_hr_test_expense_create_invoice(self): + # We add 2 expenses + expenses = self.expense + self.expense2 + sheet = self._action_submit_expenses(expenses) + self.assertIn(self.expense, sheet.expense_line_ids) + self.assertIn(self.expense2, sheet.expense_line_ids) + self.expense.action_expense_create_invoice() + self.assertTrue(self.expense.invoice_id) + self.assertAlmostEqual(self.expense.invoice_id.message_attachment_count, 1) + self.assertEqual(sheet.invoice_count, 1) + sheet.invalidate_recordset() + self.expense2.action_expense_create_invoice() + self.assertTrue(self.expense2.invoice_id) + self.assertAlmostEqual(self.expense2.invoice_id.message_attachment_count, 1) + self.assertEqual(sheet.invoice_count, 2) + # Only change invoice not assigned to expense yet + with self.assertRaises(ValidationError): + self.expense.invoice_id.amount_total = 60 + # Force to change + invoice = self.expense2.invoice_id + self.expense2.invoice_id = False + invoice.amount_total = 50 + self.assertEqual( + self.expense2.total_amount_currency, self.product_a.standard_price + ) + # Set invoice_id again to expense2 + self.expense2.invoice_id = invoice + # Validate invoices + self.expense.invoice_id.partner_id = self.partner_a + self.expense.invoice_id.action_post() + self.expense2.invoice_id.partner_id = self.partner_a + self.expense2.invoice_id.action_post() + # We approve sheet + sheet.action_approve_expense_sheets() + # We post journal entries + sheet.action_sheet_move_post() + + def test_4_hr_expense_constraint(self): + # Only invoice with status open is allowed + with self.assertRaises(UserError): + self.expense.write({"invoice_id": self.invoice.id}) + sheet = self._action_submit_expenses(self.expense) + self.expense.invoice_id = self.invoice + self.invoice.action_post() + self.expense.total_amount_currency = 80 + # Amount must equal, expense vs invoice + with self.assertRaises(UserError): + sheet._validate_expense_invoice() + self.expense.total_amount_currency = 100.0 + sheet._validate_expense_invoice() + + def test_5_hr_expense_invoice_no_duplicate_accounting_entries(self): + """Test that expenses linked to invoices don't create + duplicate accounting entries.""" + sheet = self._action_submit_expenses(self.expense + self.expense2) + self.invoice.action_post() + with Form(self.expense) as f: + f.invoice_id = self.invoice + sheet.action_approve_expense_sheets() + sheet.action_sheet_move_post() + self.assertEqual(len(sheet.account_move_ids[0].invoice_line_ids), 1) + self.assertEqual( + sheet.account_move_ids[0].invoice_line_ids.price_total, + self.expense2.total_amount, + ) + self.assertEqual( + sheet.account_move_ids[1].amount_total, + self.expense.total_amount, + ) + + def test_6_hr_expense_mixed_invoice_same_sheet(self): + # We add 3 expenses + self.expense.price_unit = 10 + self.expense2.price_unit = 20 + self.expense3.price_unit = 30 + expenses = self.expense + self.expense2 + self.expense3 + sheet = self._action_submit_expenses(expenses) + self.assertIn(self.expense, sheet.expense_line_ids) + self.assertIn(self.expense2, sheet.expense_line_ids) + self.assertIn(self.expense3, sheet.expense_line_ids) + # We add invoices to expenses 1 and 2 + self.invoice.action_post() + self.invoice2.action_post() + self.expense.invoice_id = self.invoice.id + self.expense2.invoice_id = self.invoice2.id + # We approve sheet + sheet.action_approve_expense_sheets() + self.assertEqual(sheet.state, "approve") + self.assertFalse(sheet.account_move_ids) + # We post journal entries + sheet.action_sheet_move_post() + self.assertEqual(sheet.state, "post") + self.assertEqual(self.invoice.payment_state, "paid") + self.assertEqual(self.invoice2.payment_state, "paid") + # 2 ap moves and 1 vendor bill + self.assertEqual(len(sheet.account_move_ids), 3) diff --git a/hr_expense_invoice/views/account_move_views.xml b/hr_expense_invoice/views/account_move_views.xml new file mode 100644 index 000000000..cb29e454c --- /dev/null +++ b/hr_expense_invoice/views/account_move_views.xml @@ -0,0 +1,25 @@ + + + + account.move.form - Add expense smart-button + account.move + + +
+ + +
+
+
+
diff --git a/hr_expense_invoice/views/hr_expense_views.xml b/hr_expense_invoice/views/hr_expense_views.xml new file mode 100644 index 000000000..0731a44bd --- /dev/null +++ b/hr_expense_invoice/views/hr_expense_views.xml @@ -0,0 +1,129 @@ + + + + hr.expense.form + hr.expense + + + + 1 + + + + + + + + + + + + 1 + + + 1 + + + 1 + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + hr.expense.sheet.form.inherit.sale.expense + hr.expense.sheet + + + + + + + + + + + + +