Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions hr_expense_payment/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

==================
HR Expense Payment
==================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:a4877247ec13add9edf6cb6f2a5251731ecb0da24f8c9ac64988a591086779d3
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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_payment
: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_payment
: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 links each employee-paid expense to the payment(s) that
settled it, in both directions: ``hr.expense.payment_ids`` and
``account.payment.reconciled_expense_ids``.

Both fields are computed from core's move-level link data — reconciled
payments, partials included, and payments matched by the payment
register — so nothing is stored that could go stale. Core's own
``account.payment.expense_ids`` covers company-paid expenses; these
fields cover the employee-reimbursement direction.

**Table of contents**

.. contents::
:local:

Usage
=====

Both fields are read-only, searchable, and readable by employees on
their own expenses; use them in views, filters, automations or dependent
modules.

Upgrading from 18.0: links the accounting data cannot rebuild are
carried onto the expenses' journal entries by
``migrations/19.0.1.0.0/post-migration.py``.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/hr-expense/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 <https://github.com/OCA/hr-expense/issues/new?body=module:%20hr_expense_payment%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* Tecnativa
* Ecosoft

Contributors
------------

- Saran Lim. <saranl@ecosoft.co.th>
- Manuel Regidor <manuel.regidor@sygel.es>
- ``APSL <https://apsl.tech>``\ \_\_:

- Antoni Marroig <amarroig@apsl.net>

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 <https://github.com/OCA/hr-expense/tree/19.0/hr_expense_payment>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions hr_expense_payment/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import models
15 changes: 15 additions & 0 deletions hr_expense_payment/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2019 Tecnativa - Ernesto Tejeda
# Copyright 2021 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "HR Expense Payment",
"version": "19.0.1.0.0",
"category": "Human Resources",
"author": "Tecnativa, Ecosoft, Odoo Community Association (OCA)",
"license": "AGPL-3",
"website": "https://github.com/OCA/hr-expense",
"depends": ["hr_expense"],
"data": [],
"installable": True,
}
39 changes: 39 additions & 0 deletions hr_expense_payment/i18n/hr_expense_payment.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_expense_payment
#
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_payment
#: model:ir.model,name:hr_expense_payment.model_hr_expense_sheet
msgid "Expense Report"
msgstr ""

#. module: hr_expense_payment
#: model:ir.model.fields,field_description:hr_expense_payment.field_account_payment__expense_sheet_ids
msgid "Expense sheet"
msgstr ""

#. module: hr_expense_payment
#: model:ir.model,name:hr_expense_payment.model_account_payment_register
msgid "Pay"
msgstr ""

#. module: hr_expense_payment
#: model:ir.model.fields,field_description:hr_expense_payment.field_hr_expense_sheet__payment_ids
msgid "Payment"
msgstr ""

#. module: hr_expense_payment
#: model:ir.model,name:hr_expense_payment.model_account_payment
msgid "Payments"
msgstr ""
48 changes: 48 additions & 0 deletions hr_expense_payment/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_expense_payment
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-01-09 11:06+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"

#. module: hr_expense_payment
#: model:ir.model,name:hr_expense_payment.model_hr_expense_sheet
msgid "Expense Report"
msgstr "Nota spese"

#. module: hr_expense_payment
#: model:ir.model.fields,field_description:hr_expense_payment.field_account_payment__expense_sheet_ids
msgid "Expense sheet"
msgstr "Foglio spesa"

#. module: hr_expense_payment
#: model:ir.model,name:hr_expense_payment.model_account_payment_register
msgid "Pay"
msgstr "Paga"

#. module: hr_expense_payment
#: model:ir.model.fields,field_description:hr_expense_payment.field_hr_expense_sheet__payment_ids
msgid "Payment"
msgstr "Pagamento"

#. module: hr_expense_payment
#: model:ir.model,name:hr_expense_payment.model_account_payment
msgid "Payments"
msgstr "Pagamenti"

#~ msgid "Register Payment"
#~ msgstr "Registra pagamento"

#~ msgid "Expense"
#~ msgstr "Spesa"
53 changes: 53 additions & 0 deletions hr_expense_payment/migrations/19.0.1.0.0/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2026 Don Kendall
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

import logging

from odoo.tools.sql import table_exists

_logger = logging.getLogger(__name__)

LEGACY_RELATION = "payment_expense_sheet_rel"


def migrate(cr, version):
"""Carry 18.0 rel rows whose reconciliation was since undone into core's
account_move__account_payment, via hr.expense.former_sheet_id (the legacy
pointer upgrade tools fill). Wizard-recorded links already live there and
survive on their own. Idempotent; no-op when the table is absent or the
pointer was left unfilled.
"""
if not table_exists(cr, LEGACY_RELATION):
return
cr.execute("SELECT COUNT(*) FROM hr_expense WHERE former_sheet_id IS NOT NULL")
if not cr.fetchone()[0]:
_logger.warning(
"%s exists but hr_expense.former_sheet_id is unfilled; the "
"upgrade path kept no sheet mapping, no links carried.",
LEGACY_RELATION,
)
return
cr.execute(
"""
INSERT INTO account_move__account_payment (invoice_id, payment_id)
SELECT DISTINCT expense.account_move_id, legacy.payment_id
FROM payment_expense_sheet_rel AS legacy
JOIN hr_expense AS expense ON expense.former_sheet_id = legacy.sheet_id
WHERE expense.account_move_id IS NOT NULL
AND EXISTS (
SELECT 1 FROM account_payment AS payment
WHERE payment.id = legacy.payment_id
)
AND NOT EXISTS (
SELECT 1 FROM account_move__account_payment AS existing
WHERE existing.invoice_id = expense.account_move_id
AND existing.payment_id = legacy.payment_id
)
"""
)
_logger.info(
"hr_expense_payment: carried %s payment link(s) from %s onto the "
"expense journal entries.",
cr.rowcount,
LEGACY_RELATION,
)
4 changes: 4 additions & 0 deletions hr_expense_payment/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import account_payment
from . import hr_expense
36 changes: 36 additions & 0 deletions hr_expense_payment/models/account_payment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright 2019 Tecnativa - Ernesto Tejeda
# Copyright 2021 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models


class AccountPayment(models.Model):
_inherit = "account.payment"

reconciled_expense_ids = fields.Many2many(
comodel_name="hr.expense",
string="Reimbursed Expenses",
compute="_compute_reconciled_expense_ids",
compute_sudo=True,
search="_search_reconciled_expense_ids",
help="Employee-paid expenses whose journal entry is linked to this "
"payment, by reconciliation or by the payment register.",
)

@api.depends(
"invoice_ids",
"move_id.line_ids.matched_debit_ids",
"move_id.line_ids.matched_credit_ids",
)
def _compute_reconciled_expense_ids(self):
for payment in self:
payment.reconciled_expense_ids = (
payment.invoice_ids | payment.reconciled_bill_ids
).expense_ids

def _search_reconciled_expense_ids(self, operator, value):
if operator not in ("in", "="):
return NotImplemented
expenses = self.env["hr.expense"].browse(value)
return [("id", "in", expenses.payment_ids.ids)]
34 changes: 34 additions & 0 deletions hr_expense_payment/models/hr_expense.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright 2019 Tecnativa - Ernesto Tejeda
# Copyright 2021 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models


class HrExpense(models.Model):
_inherit = "hr.expense"

payment_ids = fields.Many2many(
comodel_name="account.payment",
string="Payments",
compute="_compute_payment_ids",
compute_sudo=True,
search="_search_payment_ids",
help="Payments linked to this expense's journal entry, whether "
"reconciled with it or matched by the payment register.",
)

@api.depends(
"account_move_id.line_ids.matched_debit_ids",
"account_move_id.line_ids.matched_credit_ids",
"account_move_id.matched_payment_ids",
)
def _compute_payment_ids(self):
for expense in self:
expense.payment_ids = expense.account_move_id.reconciled_payment_ids

def _search_payment_ids(self, operator, value):
if operator not in ("in", "="):
return NotImplemented
payments = self.env["account.payment"].browse(value)
return [("id", "in", payments.reconciled_expense_ids.ids)]
3 changes: 3 additions & 0 deletions hr_expense_payment/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
4 changes: 4 additions & 0 deletions hr_expense_payment/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Saran Lim. \<<saranl@ecosoft.co.th>\>
- Manuel Regidor \<<manuel.regidor@sygel.es>\>
- `APSL <https://apsl.tech>`__:
- Antoni Marroig \<<amarroig@apsl.net>\>
9 changes: 9 additions & 0 deletions hr_expense_payment/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This module links each employee-paid expense to the payment(s) that settled
it, in both directions: `hr.expense.payment_ids` and
`account.payment.reconciled_expense_ids`.

Both fields are computed from core's move-level link data — reconciled
payments, partials included, and payments matched by the payment register —
so nothing is stored that could go stale. Core's own
`account.payment.expense_ids` covers company-paid expenses; these fields
cover the employee-reimbursement direction.
5 changes: 5 additions & 0 deletions hr_expense_payment/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Both fields are read-only, searchable, and readable by employees on their
own expenses; use them in views, filters, automations or dependent modules.

Upgrading from 18.0: links the accounting data cannot rebuild are carried
onto the expenses' journal entries by `migrations/19.0.1.0.0/post-migration.py`.
Binary file added hr_expense_payment/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading