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
6 changes: 1 addition & 5 deletions hr_expense_petty_cash/README.rst
Original file line number Diff line number Diff line change
@@ -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
==========
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions hr_expense_petty_cash/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
1 change: 1 addition & 0 deletions hr_expense_petty_cash/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
from . import hr_expense
from . import hr_expense_sheet
from . import petty_cash
from . import petty_cash_transaction
20 changes: 20 additions & 0 deletions hr_expense_petty_cash/models/petty_cash.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
109 changes: 109 additions & 0 deletions hr_expense_petty_cash/models/petty_cash_transaction.py
Original file line number Diff line number Diff line change
@@ -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'")
1 change: 1 addition & 0 deletions hr_expense_petty_cash/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions hr_expense_petty_cash/security/petty_cash_security.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@
['|',('company_id','=',False),('company_id','in',company_ids)]
</field>
</record>
<record id="petty_cash_transaction_rule" model="ir.rule">
<field name="name">Petty Cash Transaction multi-company</field>
<field name="model_id" ref="model_petty_cash_transaction" />
<field name="global" eval="True" />
<field name="domain_force">
['|',('company_id','=',False),('company_id','in',company_ids)]
</field>
</record>
</odoo>
28 changes: 11 additions & 17 deletions hr_expense_petty_cash/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<title>Petty Cash</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,21 +360,16 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="petty-cash">
<h1 class="title">Petty Cash</h1>


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="petty-cash">
<h1>Petty Cash</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:c45aec15c833678152a0e85a581888707b35a97d01d43b65b09fe6f82eec8bdc
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/hr-expense/tree/18.0/hr_expense_petty_cash"><img alt="OCA/hr-expense" src="https://img.shields.io/badge/github-OCA%2Fhr--expense-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/hr-expense-18-0/hr-expense-18-0-hr_expense_petty_cash"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/hr-expense&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/hr-expense/tree/18.0/hr_expense_petty_cash"><img alt="OCA/hr-expense" src="https://img.shields.io/badge/github-OCA%2Fhr--expense-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/hr-expense-18-0/hr-expense-18-0-hr_expense_petty_cash"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/hr-expense&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module work about expense that paid by petty cash.</p>
<p>General Process:</p>
<ol class="arabic simple">
Expand All @@ -401,7 +396,7 @@ <h1>Petty Cash</h1>
</ul>
</div>
<div class="section" id="configuration">
<h2><a class="toc-backref" href="#toc-entry-1">Configuration</a></h2>
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p><strong>Create a Petty Cash Account</strong></p>
<ol class="arabic simple">
<li>Go to Invoicing &gt; Accounting &gt; Petty Cash</li>
Expand All @@ -415,7 +410,7 @@ <h2><a class="toc-backref" href="#toc-entry-1">Configuration</a></h2>
</ul>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-2">Usage</a></h2>
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p><strong>Create a Petty Cash Holder</strong></p>
<ol class="arabic simple">
<li>Go to Invoicing &gt; Accounting &gt; Petty Cash</li>
Expand Down Expand Up @@ -446,23 +441,23 @@ <h2><a class="toc-backref" href="#toc-entry-2">Usage</a></h2>
you configure journal in petty cash holder.</p>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h2>
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/hr-expense/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/hr-expense/issues/new?body=module:%20hr_expense_petty_cash%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-4">Credits</a></h2>
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-5">Authors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple">
<li>Ecosoft</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-6">Contributors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://ecosoft.co.th">Ecosoft</a>:<ul>
<li>Pimolnat Suntian &lt;<a class="reference external" href="mailto:pimolnats&#64;ecosoft.co.th">pimolnats&#64;ecosoft.co.th</a>&gt;</li>
Expand All @@ -480,7 +475,7 @@ <h3><a class="toc-backref" href="#toc-entry-6">Contributors</a></h3>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h3>
<h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand All @@ -493,6 +488,5 @@ <h3><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h3>
</div>
</div>
</div>
</div>
</body>
</html>
27 changes: 27 additions & 0 deletions hr_expense_petty_cash/tests/test_hr_expense_petty_cash.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -276,13 +290,26 @@ 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()
self.assertEqual(len(sheet.account_move_ids), 1)
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)
Expand Down
Loading
Loading