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
17 changes: 12 additions & 5 deletions payroll/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

=======
Payroll
=======
Expand All @@ -17,7 +13,7 @@ Payroll
.. |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-LGPL--3-blue.png
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpayroll-lightgray.png?logo=github
Expand All @@ -38,6 +34,16 @@ This module is a backport from Odoo SA and as such, it is not included
in the OCA CLA. That means we do not have a copy of the copyright on it
like all other OCA modules.

Opening Values
--------------

Each contract exposes an **Opening Values** tab to carry over reference
data when migrating from another payroll system: seniority date, opening
date, opening paid leave base and opening paid leave days balance. These
fields are created for use by each country's localization modules; in
this module alone they are only informational and drive no computation.
They become read-only once a payslip exists for the contract.

**Table of contents**

.. contents::
Expand Down Expand Up @@ -70,6 +76,7 @@ Contributors
- Nimarosa (Nicolas Rodriguez) <nicolarsande@gmail.com>
- Henrik Norlin (@appstogrow)
- Régis Pirard <regis.pirard@tincid.com>
- Cyril VINH-TUNG <cyril@invitu.com>

Maintainers
-----------
Expand Down
37 changes: 36 additions & 1 deletion payroll/models/hr_contract.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import fields, models
from odoo import api, fields, models


class HrContract(models.Model):
Expand Down Expand Up @@ -32,6 +32,41 @@ class HrContract(models.Model):
required=True, help="Employee's working schedule."
)

seniority_date = fields.Date(
help="Starting date used for seniority computation.",
)

opening_date = fields.Date(
help="Cut-off date of the opening balances, not necessarily the "
"contract start; payslips dated after it take over from these values.",
)
opening_leave_base = fields.Monetary(
string="Opening Paid Leave Base",
currency_field="currency_id",
help="Cumulative paid leave reference base at the opening date.",
)
opening_leave_days = fields.Float(
string="Opening Paid Leave Days Balance",
digits=(16, 2),
help="Paid leave days acquired and not yet taken at the opening date.",
)

payslip_ids = fields.One2many(
"hr.payslip",
"contract_id",
string="Payslips",
help="Payslips generated for this contract.",
)
payslip_count = fields.Integer(
compute="_compute_payslip_count",
help="Number of payslips on the contract; locks the opening fields.",
)

@api.depends("payslip_ids")
def _compute_payslip_count(self):
for contract in self:
contract.payslip_count = len(contract.payslip_ids)

def get_all_structures(self):
"""
@return: the structures linked to the given contracts, ordered by
Expand Down
1 change: 1 addition & 0 deletions payroll/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
- Nimarosa (Nicolas Rodriguez) \<<nicolarsande@gmail.com>\>
- Henrik Norlin (@appstogrow)
- Régis Pirard \<<regis.pirard@tincid.com>\>
- Cyril VINH-TUNG \<<cyril@invitu.com>\>
9 changes: 9 additions & 0 deletions payroll/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@ Manage your employee payroll records.
This module is a backport from Odoo SA and as such, it is not included
in the OCA CLA. That means we do not have a copy of the copyright on it
like all other OCA modules.

## Opening Values

Each contract exposes an **Opening Values** tab to carry over reference
data when migrating from another payroll system: seniority date, opening
date, opening paid leave base and opening paid leave days balance. These
fields are created for use by each country's localization modules; in
this module alone they are only informational and drive no computation.
They become read-only once a payslip exists for the contract.
39 changes: 19 additions & 20 deletions payroll/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>Payroll</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,35 +360,33 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="payroll">
<h1 class="title">Payroll</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="payroll">
<h1>Payroll</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:48358dad5a9a5f23185ec6c0d86301e929ef3cce8d42739b463c6c5d0594ace1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/license-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/payroll/tree/18.0/payroll"><img alt="OCA/payroll" src="https://img.shields.io/badge/github-OCA%2Fpayroll-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/payroll-18-0/payroll-18-0-payroll"><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/payroll&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/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/payroll/tree/18.0/payroll"><img alt="OCA/payroll" src="https://img.shields.io/badge/github-OCA%2Fpayroll-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/payroll-18-0/payroll-18-0-payroll"><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/payroll&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>Manage your employee payroll records.</p>
<p>This module is a backport from Odoo SA and as such, it is not included
in the OCA CLA. That means we do not have a copy of the copyright on it
like all other OCA modules.</p>
<div class="section" id="opening-values">
<h1>Opening Values</h1>
<p>Each contract exposes an <strong>Opening Values</strong> tab to carry over reference
data when migrating from another payroll system: seniority date, opening
date, opening paid leave base and opening paid leave days balance. These
fields are created for use by each country’s localization modules; in
this module alone they are only informational and drive no computation.
They become read-only once a payslip exists for the contract.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
</ul>
</li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a></li>
</ul>
</div>
<div class="section" id="bug-tracker">
Expand All @@ -401,25 +399,28 @@ <h2><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h2>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-2">Credits</a></h2>
</div>
</div>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-3">Authors</a></h3>
<h1>Authors</h1>
<ul class="simple">
<li>Odoo SA</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-4">Contributors</a></h3>
<h1>Contributors</h1>
<ul class="simple">
<li>Odoo SA &lt;<a class="reference external" href="mailto:info&#64;odoo.com">info&#64;odoo.com</a>&gt;</li>
<li>David James &lt;<a class="reference external" href="mailto:david&#64;djdc.net.au">david&#64;djdc.net.au</a>&gt;</li>
<li>Hilar AK &lt;<a class="reference external" href="mailto:hilarak&#64;gmail.com">hilarak&#64;gmail.com</a>&gt;</li>
<li>Nimarosa (Nicolas Rodriguez) &lt;<a class="reference external" href="mailto:nicolarsande&#64;gmail.com">nicolarsande&#64;gmail.com</a>&gt;</li>
<li>Henrik Norlin (&#64;appstogrow)</li>
<li>Régis Pirard &lt;<a class="reference external" href="mailto:regis.pirard&#64;tincid.com">regis.pirard&#64;tincid.com</a>&gt;</li>
<li>Cyril VINH-TUNG &lt;<a class="reference external" href="mailto:cyril&#64;invitu.com">cyril&#64;invitu.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h3>
<h1>Maintainers</h1>
<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 @@ -433,7 +434,5 @@ <h3><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h3>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</div>
</body>
</html>
1 change: 1 addition & 0 deletions payroll/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from . import test_browsable_object
from . import test_hr_contract_opening
from . import test_hr_payslip_worked_days
from . import test_hr_salary_rule
from . import test_payslip_flow
Expand Down
60 changes: 60 additions & 0 deletions payroll/tests/test_hr_contract_opening.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo.fields import Date

from .common import TestPayslipBase


class TestHrContractOpening(TestPayslipBase):
def setUp(self):
super().setUp()
self.employee = self.env["hr.employee"].create({"name": "Test Employee"})
self.contract = self.Contract.create(
{
"name": "Test Contract",
"employee_id": self.employee.id,
"wage": 200000.0,
"state": "open",
"date_start": Date.from_string("2026-01-01"),
}
)

def test_opening_fields_default(self):
"""Opening fields are empty by default and contract has no payslips."""
self.assertFalse(self.contract.opening_date)
self.assertFalse(self.contract.seniority_date)
self.assertEqual(self.contract.opening_leave_base, 0.0)
self.assertEqual(self.contract.opening_leave_days, 0.0)
self.assertEqual(self.contract.payslip_count, 0)

def test_opening_fields_writable(self):
"""Opening fields can be written when no payslip exists."""
self.contract.write(
{
"opening_date": Date.from_string("2026-05-31"),
"seniority_date": Date.from_string("2018-03-15"),
"opening_leave_base": 1200000.0,
"opening_leave_days": 12.5,
}
)
self.assertEqual(self.contract.opening_date, Date.from_string("2026-05-31"))
self.assertEqual(
self.contract.seniority_date,
Date.from_string("2018-03-15"),
)
self.assertEqual(self.contract.opening_leave_base, 1200000.0)
self.assertEqual(self.contract.opening_leave_days, 12.5)

def test_payslip_count(self):
"""payslip_count reflects the number of payslips for the contract."""
self.assertEqual(self.contract.payslip_count, 0)
self.Payslip.create(
{
"name": "Test Payslip",
"employee_id": self.employee.id,
"contract_id": self.contract.id,
"date_from": Date.from_string("2026-06-01"),
"date_to": Date.from_string("2026-06-30"),
}
)
self.assertEqual(self.contract.payslip_count, 1)
21 changes: 21 additions & 0 deletions payroll/views/hr_contract_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@
<field name="company_id" groups="base.group_multi_company" />
<field name="currency_id" invisible="1" />
</xpath>
<xpath expr="//notebook" position="inside">
<page string="Opening Values" name="opening_values">
<field name="payslip_count" invisible="1" />
<group>
<field name="seniority_date" readonly="payslip_count &gt; 0" />
<field name="opening_date" readonly="payslip_count &gt; 0" />
<field
name="opening_leave_base"
readonly="payslip_count &gt; 0"
/>
<field
name="opening_leave_days"
readonly="payslip_count &gt; 0"
/>
</group>
<p class="text-muted" invisible="payslip_count == 0">
Opening values are locked once payslips exist for this
contract.
</p>
</page>
</xpath>
</field>
</record>
</odoo>
Loading