From b4c699ddb7a727e18b8ca91accb120e2a2b095e4 Mon Sep 17 00:00:00 2001 From: Saran440 Date: Fri, 19 Jun 2026 09:45:26 +0700 Subject: [PATCH] [IMP] hr_expense_petty_cash: add history petty cash --- hr_expense_petty_cash/README.rst | 6 +- hr_expense_petty_cash/__manifest__.py | 1 + hr_expense_petty_cash/models/__init__.py | 1 + hr_expense_petty_cash/models/petty_cash.py | 20 ++++ .../models/petty_cash_transaction.py | 109 ++++++++++++++++++ .../security/ir.model.access.csv | 1 + .../security/petty_cash_security.xml | 8 ++ .../static/description/index.html | 28 ++--- .../tests/test_hr_expense_petty_cash.py | 27 +++++ .../views/petty_cash_transaction_views.xml | 71 ++++++++++++ .../views/petty_cash_views.xml | 15 +++ 11 files changed, 265 insertions(+), 22 deletions(-) create mode 100644 hr_expense_petty_cash/models/petty_cash_transaction.py create mode 100644 hr_expense_petty_cash/views/petty_cash_transaction_views.xml diff --git a/hr_expense_petty_cash/README.rst b/hr_expense_petty_cash/README.rst index 76c23219c..3b4687222 100644 --- a/hr_expense_petty_cash/README.rst +++ b/hr_expense_petty_cash/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ========== Petty Cash ========== @@ -17,7 +13,7 @@ Petty Cash .. |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 +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fhr--expense-lightgray.png?logo=github diff --git a/hr_expense_petty_cash/__manifest__.py b/hr_expense_petty_cash/__manifest__.py index 6b55b428e..e5c10c77c 100644 --- a/hr_expense_petty_cash/__manifest__.py +++ b/hr_expense_petty_cash/__manifest__.py @@ -16,6 +16,7 @@ "views/hr_expense_sheet_views.xml", "views/hr_expense_views.xml", "views/petty_cash_views.xml", + "views/petty_cash_transaction_views.xml", ], "installable": True, } diff --git a/hr_expense_petty_cash/models/__init__.py b/hr_expense_petty_cash/models/__init__.py index e60741242..6d5b181f7 100644 --- a/hr_expense_petty_cash/models/__init__.py +++ b/hr_expense_petty_cash/models/__init__.py @@ -5,3 +5,4 @@ from . import hr_expense from . import hr_expense_sheet from . import petty_cash +from . import petty_cash_transaction diff --git a/hr_expense_petty_cash/models/petty_cash.py b/hr_expense_petty_cash/models/petty_cash.py index 8adcae0b0..0d68e5c31 100644 --- a/hr_expense_petty_cash/models/petty_cash.py +++ b/hr_expense_petty_cash/models/petty_cash.py @@ -31,6 +31,10 @@ class PettyCash(models.Model): string="Balance", compute="_compute_petty_cash_balance", ) + transaction_count = fields.Integer( + string="Transactions", + compute="_compute_transaction_count", + ) journal_id = fields.Many2one( comodel_name="account.journal", check_company=True, @@ -62,3 +66,19 @@ def _compute_petty_cash_balance(self): ) balance = sum(line.debit - line.credit for line in aml) rec.petty_cash_balance = balance + + def _compute_transaction_count(self): + transaction_env = self.env["petty.cash.transaction"] + for rec in self: + rec.transaction_count = transaction_env.search_count( + [("petty_cash_id", "=", rec.id)] + ) + + def action_open_transactions(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "hr_expense_petty_cash.action_petty_cash_transaction" + ) + action["domain"] = [("petty_cash_id", "=", self.id)] + action["context"] = {"default_petty_cash_id": self.id} + return action diff --git a/hr_expense_petty_cash/models/petty_cash_transaction.py b/hr_expense_petty_cash/models/petty_cash_transaction.py new file mode 100644 index 000000000..cb2bd6de7 --- /dev/null +++ b/hr_expense_petty_cash/models/petty_cash_transaction.py @@ -0,0 +1,109 @@ +# Copyright 2026 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.tools.sql import SQL + + +class PettyCashTransaction(models.Model): + _name = "petty.cash.transaction" + _description = "Petty Cash Transaction" + _auto = False + _order = "id desc" + + _depends = { + "account.move.line": [ + "date", + "debit", + "credit", + "partner_id", + "account_id", + "move_id", + "company_id", + "parent_state", + "expense_id", + ], + "account.move": ["name", "is_petty_cash", "expense_sheet_id"], + "petty.cash": ["partner_id", "account_id", "company_id"], + } + + date = fields.Date() + name = fields.Char() + petty_cash_id = fields.Many2one( + comodel_name="petty.cash", + string="Petty Cash Holder", + ) + move_id = fields.Many2one( + comodel_name="account.move", + string="Document", + ) + sheet_id = fields.Many2one( + comodel_name="hr.expense.sheet", + string="Expense Report", + ) + expense_id = fields.Many2one( + comodel_name="hr.expense", + ) + partner_id = fields.Many2one(comodel_name="res.partner") + account_id = fields.Many2one(comodel_name="account.account") + source = fields.Selection( + selection=[ + ("refill", "Refill"), + ("expense", "Expense"), + ], + ) + debit = fields.Float() + credit = fields.Float() + amount = fields.Float() + balance = fields.Float() + company_id = fields.Many2one(comodel_name="res.company") + + @property + def _table_query(self) -> SQL: + return SQL("%s %s %s", self._select(), self._from(), self._where()) + + @api.model + def _select(self) -> SQL: + return SQL( + """ + SELECT + aml.id AS id, + aml.date AS date, + am.name AS name, + pc.id AS petty_cash_id, + aml.move_id AS move_id, + am.expense_sheet_id AS sheet_id, + aml.expense_id AS expense_id, + aml.partner_id AS partner_id, + aml.account_id AS account_id, + CASE + WHEN am.is_petty_cash THEN 'refill' + WHEN am.expense_sheet_id IS NOT NULL THEN 'expense' + END AS source, + aml.debit AS debit, + aml.credit AS credit, + (aml.debit - aml.credit) AS amount, + SUM(aml.debit - aml.credit) OVER ( + PARTITION BY pc.id + ORDER BY aml.date, aml.id + ) AS balance, + aml.company_id AS company_id + """ + ) + + @api.model + def _from(self) -> SQL: + return SQL( + """ + FROM account_move_line aml + JOIN account_move am ON am.id = aml.move_id + JOIN petty_cash pc + ON pc.partner_id = aml.partner_id + AND pc.account_id = aml.account_id + AND pc.company_id = aml.company_id + """ + ) + + @api.model + def _where(self) -> SQL: + return SQL("WHERE aml.parent_state = 'posted'") diff --git a/hr_expense_petty_cash/security/ir.model.access.csv b/hr_expense_petty_cash/security/ir.model.access.csv index 149f12a4e..8299b460f 100644 --- a/hr_expense_petty_cash/security/ir.model.access.csv +++ b/hr_expense_petty_cash/security/ir.model.access.csv @@ -1,3 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_hr_expense_petty_cash,access_hr_expense_petty_cash,model_petty_cash,account.group_account_user,1,1,1,1 access_hr_expense_petty_cash_user,access_hr_expense_petty_cash_user,model_petty_cash,base.group_user,1,0,0,0 +access_petty_cash_transaction,access_petty_cash_transaction,model_petty_cash_transaction,account.group_account_user,1,0,0,0 diff --git a/hr_expense_petty_cash/security/petty_cash_security.xml b/hr_expense_petty_cash/security/petty_cash_security.xml index 94ca0b39c..4bc69dd59 100644 --- a/hr_expense_petty_cash/security/petty_cash_security.xml +++ b/hr_expense_petty_cash/security/petty_cash_security.xml @@ -7,4 +7,12 @@ ['|',('company_id','=',False),('company_id','in',company_ids)] + + Petty Cash Transaction multi-company + + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + diff --git a/hr_expense_petty_cash/static/description/index.html b/hr_expense_petty_cash/static/description/index.html index 02f030e69..6da9cb601 100644 --- a/hr_expense_petty_cash/static/description/index.html +++ b/hr_expense_petty_cash/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Petty Cash -
+
+

Petty Cash

- - -Odoo Community Association - -
-

Petty Cash

-

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

+

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

This module work about expense that paid by petty cash.

General Process:

    @@ -401,7 +396,7 @@

    Petty Cash

-

Configuration

+

Configuration

Create a Petty Cash Account

  1. Go to Invoicing > Accounting > Petty Cash
  2. @@ -415,7 +410,7 @@

    Configuration

-

Usage

+

Usage

Create a Petty Cash Holder

  1. Go to Invoicing > Accounting > Petty Cash
  2. @@ -446,7 +441,7 @@

    Usage

    you configure journal in petty cash holder.

-

Bug Tracker

+

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 @@ -454,15 +449,15 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Ecosoft
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -493,6 +488,5 @@

Maintainers

-
diff --git a/hr_expense_petty_cash/tests/test_hr_expense_petty_cash.py b/hr_expense_petty_cash/tests/test_hr_expense_petty_cash.py index 4a42153b1..b85bac96a 100644 --- a/hr_expense_petty_cash/tests/test_hr_expense_petty_cash.py +++ b/hr_expense_petty_cash/tests/test_hr_expense_petty_cash.py @@ -20,6 +20,7 @@ def setUpClass(cls): cls.move_obj = cls.env["account.move"] cls.sheet_obj = cls.env["hr.expense.sheet"] cls.exp_obj = cls.env["hr.expense"] + cls.pc_transaction_obj = cls.env["petty.cash.transaction"] # Demo data cls.employee_1 = cls.env.ref("hr.employee_admin") @@ -221,6 +222,19 @@ def test_02_create_expense_petty_cash(self): invoice.action_post() self.petty_cash_holder._compute_petty_cash_balance() self.assertEqual(self.petty_cash_holder.petty_cash_balance, 1000.0) + self.assertEqual(self.petty_cash_holder.transaction_count, 1) + transactions = self.pc_transaction_obj.search( + [("petty_cash_id", "=", self.petty_cash_holder.id)] + ) + self.assertEqual(len(transactions), 1) + refill = transactions[0] + self.assertEqual(refill.source, "refill") + self.assertEqual(refill.debit, 1000.0) + self.assertEqual(refill.credit, 0.0) + self.assertEqual(refill.balance, 1000.0) + self.assertTrue(refill.move_id) + self.assertFalse(refill.sheet_id) + # Create expense expense_own = self._create_expense(400.0, self.employee_1, "own_account") expense_petty_cash = self._create_expense( @@ -276,6 +290,12 @@ def test_02_create_expense_petty_cash(self): self.assertEqual(sheet.state, "post") self.assertTrue(sheet.account_move_ids.id) self.assertEqual(self.petty_cash_holder.petty_cash_balance, 600.0) + # Check transactions after expense + self.assertEqual(self.petty_cash_holder.transaction_count, 2) + transactions = self.pc_transaction_obj.search( + [("petty_cash_id", "=", self.petty_cash_holder.id)] + ) + self.assertEqual(len(transactions), 2) # Check action action = sheet.action_open_account_moves() @@ -283,6 +303,13 @@ def test_02_create_expense_petty_cash(self): self.assertEqual(action["res_model"], "account.move") self.assertEqual(action["res_id"], sheet.account_move_ids.id) + action = self.petty_cash_holder.action_open_transactions() + self.assertEqual(action["res_model"], "petty.cash.transaction") + self.assertEqual( + action["domain"], + [("petty_cash_id", "=", self.petty_cash_holder.id)], + ) + def test_03_create_expense_petty_cash_with_journal(self): self.petty_cash_holder.journal_id = self.petty_cash_journal_id invoice = self._create_invoice(self.partner_1.id) diff --git a/hr_expense_petty_cash/views/petty_cash_transaction_views.xml b/hr_expense_petty_cash/views/petty_cash_transaction_views.xml new file mode 100644 index 000000000..44084a938 --- /dev/null +++ b/hr_expense_petty_cash/views/petty_cash_transaction_views.xml @@ -0,0 +1,71 @@ + + + + petty.cash.transaction.list + petty.cash.transaction + + + + + + + + + + + + + + + + + petty.cash.transaction.search + petty.cash.transaction + + + + + + + + + + + + + + + + + Petty Cash Transactions + petty.cash.transaction + list + + + + diff --git a/hr_expense_petty_cash/views/petty_cash_views.xml b/hr_expense_petty_cash/views/petty_cash_views.xml index 6852390ea..ce1722d7f 100644 --- a/hr_expense_petty_cash/views/petty_cash_views.xml +++ b/hr_expense_petty_cash/views/petty_cash_views.xml @@ -12,6 +12,21 @@ bg_color="bg-danger" invisible="active" /> +
+ +