Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[12.0][ADD] hr_timesheet_sheet_prefill_multi #43

Merged
merged 9 commits into from
Oct 11, 2024
3 changes: 2 additions & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ odoo_test_flavor: OCB
odoo_version: 12.0
org_name: Coop IT Easy SC
org_slug: coopiteasy
rebel_module_groups: []
rebel_module_groups:
- hr_timesheet_sheet_prefill_multi
repo_description: hr_timesheet modules
repo_name: cie-timesheet
repo_slug: cie-timesheet
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ jobs:
matrix:
include:
- container: ghcr.io/oca/oca-ci/py3.6-ocb12.0:latest
include: "hr_timesheet_sheet_prefill_multi"
name: test with OCB
makepot: "true"
- container: ghcr.io/oca/oca-ci/py3.6-ocb12.0:latest
exclude: "hr_timesheet_sheet_prefill_multi"
name: test with OCB
makepot: "true"
services:
Expand All @@ -30,6 +35,9 @@ jobs:
POSTGRES_DB: odoo
ports:
- 5432:5432
env:
INCLUDE: "${{ matrix.include }}"
EXCLUDE: "${{ matrix.exclude }}"
steps:
- uses: actions/checkout@v3
with:
Expand Down
11 changes: 10 additions & 1 deletion hr_timesheet_sheet_prefill/models/hr_employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@
class Employee(models.Model):
_inherit = "hr.employee"

project_ids = fields.Many2many(comodel_name="project.project", string="Projects")
project_ids = fields.Many2many(
comodel_name="project.project",
relation="hr_employee_project_project_rel",
string="Projects",
)

# This exists solely for extension in hr_timesheet_sheet_prefill_multi.
def all_prefill_projects(self):
self.ensure_one()
return self.project_ids
34 changes: 18 additions & 16 deletions hr_timesheet_sheet_prefill/models/hr_timesheet_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,6 @@
class Sheet(models.Model):
_inherit = "hr_timesheet.sheet"

def get_number_days_between_dates(self, date_start, date_end):
"""
Return the number of days between two dates, including both of them.

Arguments:
date_start (date): start date
date_end (date): end date

Returns:
int: the number of days between the provided dates
"""
difference = date_end - date_start
# return result and add a day
return difference.days + 1

@api.model
def create(self, vals):
ts = super().create(vals)
Expand All @@ -37,13 +22,30 @@ def create(self, vals):
days = self.get_number_days_between_dates(date_start, date_end)
for day in range(days):
date_current = date_start + timedelta(days=day)
for project in employee_id.project_ids:
for project in employee_id.all_prefill_projects():
aal_dict = self._prepare_analytic_line(
date_current, project, sheet_id, employee_id.user_id
)
ts.write({"timesheet_ids": [(0, 0, aal_dict)]})
return ts

@api.model
def get_number_days_between_dates(self, date_start, date_end):
"""
Return the number of days between two dates, including both of them.

Arguments:
date_start (date): start date
date_end (date): end date

Returns:
int: the number of days between the provided dates
"""
difference = date_end - date_start
# return result and add a day
return difference.days + 1

@api.model
def _prepare_analytic_line(self, date, project, sheet_id, user_id):
return {
"project_id": project.id,
Expand Down
6 changes: 5 additions & 1 deletion hr_timesheet_sheet_prefill/models/project_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@
class Project(models.Model):
_inherit = "project.project"

employee_ids = fields.Many2many(comodel_name="hr.employee", string="Employees")
employee_ids = fields.Many2many(
comodel_name="hr.employee",
relation="hr_employee_project_project_rel",
string="Employees",
)
5 changes: 5 additions & 0 deletions hr_timesheet_sheet_prefill_multi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from . import models
23 changes: 23 additions & 0 deletions hr_timesheet_sheet_prefill_multi/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

{
"name": "Timesheet Sheet prefill with duplicates",
"summary": """
Allow duplicates in prefill templates.""",
carmenbianca marked this conversation as resolved.
Show resolved Hide resolved
"version": "12.0.1.0.0",
"category": "Human Resources",
"website": "https://coopiteasy.be",
"author": "Coop IT Easy SC, Odoo Community Association (OCA)",
"maintainers": ["carmenbianca"],
"license": "AGPL-3",
"application": False,
carmenbianca marked this conversation as resolved.
Show resolved Hide resolved
"depends": [
"hr_timesheet_sheet_prefill",
],
"data": [
"security/ir.model.access.csv",
"views/hr_employee_views.xml",
],
}
6 changes: 6 additions & 0 deletions hr_timesheet_sheet_prefill_multi/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from . import hr_employee
from . import hr_timesheet_sheet_prefill
25 changes: 25 additions & 0 deletions hr_timesheet_sheet_prefill_multi/models/hr_employee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from odoo import fields, models


class HrEmployee(models.Model):
_inherit = "hr.employee"

timesheet_prefill_ids = fields.One2many(
comodel_name="hr_timesheet.sheet.prefill",
inverse_name="hr_employee_id",
string="Prefill Projects",
copy=False,
)

def all_prefill_projects(self):
self.ensure_one()
# The only purpose of the below code is to sort the projects according
# to the sequence of the prefill records.
projects = self.env["project.project"].browse()
for prefill in self.timesheet_prefill_ids.sorted():
projects += prefill.project_project_id
carmenbianca marked this conversation as resolved.
Show resolved Hide resolved
return projects
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from odoo import api, fields, models


class HrTimesheetSheetPrefill(models.Model):
_name = "hr_timesheet.sheet.prefill"
_description = "Timesheet prefill line"
_order = "sequence, id"
# This is a weird hack, inspired by what is done in the `mail` module for
# the `mail.notification` model. That model, like this one, is a model
# doubling as a Many2many table. In `hr_timesheet_sheet_prefill`, the below
# Many2many relation table is created. Here, we claim that table for
# ourselves to add the functionality we want, while still preserving the
# original Many2many functionality without any changes upstream.
_table = "hr_employee_project_project_rel"
_rec_name = "project_project_id"

hr_employee_id = fields.Many2one(
string="Employee",
comodel_name="hr.employee",
ondelete="cascade",
required=True,
)
project_project_id = fields.Many2one(
string="Project",
comodel_name="project.project",
ondelete="cascade",
required=True,
)

sequence = fields.Integer(string="Sequence", default=10)

@api.model_cr
def init(self):
# Add id column if it doesn't exist yet.
self.env.cr.execute(
"""
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name='hr_employee_project_project_rel'
AND column_name='id') THEN
ALTER TABLE hr_employee_project_project_rel
ADD COLUMN id SERIAL NOT NULL PRIMARY KEY;
END IF;
END $$;
"""
)
# Get rid of the unique constraint from the Many2many relationship.
self.env.cr.execute(
"""
ALTER TABLE hr_employee_project_project_rel
DROP CONSTRAINT IF EXISTS
hr_employee_project_project_r_hr_employee_id_project_projec_key;
"""
)
3 changes: 3 additions & 0 deletions hr_timesheet_sheet_prefill_multi/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Coop IT Easy SC <https://coopiteasy.be>`_:

* Carmen Bianca BAKKER
1 change: 1 addition & 0 deletions hr_timesheet_sheet_prefill_multi/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow duplicates in prefill templates.
5 changes: 5 additions & 0 deletions hr_timesheet_sheet_prefill_multi/readme/ROADMAP.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
As part of installing this module, some adjustments are made to an existing
Many2many table. These adjustments are (presumably?) NOT undone upon
uninstallation.

A safe way to uninstall this module should be provided.
2 changes: 2 additions & 0 deletions hr_timesheet_sheet_prefill_multi/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_hr_timesheet_sheet_prefill_user,hr_timesheet.sheet.prefill.user,model_hr_timesheet_sheet_prefill,base.group_user,1,1,1,1
5 changes: 5 additions & 0 deletions hr_timesheet_sheet_prefill_multi/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from . import test_prefill_multi
83 changes: 83 additions & 0 deletions hr_timesheet_sheet_prefill_multi/tests/test_prefill_multi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# SPDX-FileCopyrightText: 2024 Coop IT Easy SC
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from odoo.tests.common import TransactionCase


class TestPrefillMulti(TransactionCase):
def setUp(self):
super().setUp()

self.project_01 = self.env["project.project"].create({"name": "Project 01"})
self.project_02 = self.env["project.project"].create({"name": "Project 02"})

self.user = self.env["res.users"].create(
{
"name": "Test",
"login": "test",
"password": "test",
}
)
self.employee = self.env["hr.employee"].create(
{
"name": "Test",
"user_id": self.user.id,
"address_id": self.user.partner_id.id,
}
)

def test_project_ids_still_works(self):
"""You can still use project_ids on hr.employee as normally. It will
create prefill records.
"""
projects = self.project_01 | self.project_02
self.employee.project_ids = projects

self.assertEqual(len(self.employee.timesheet_prefill_ids), 2)
prefill_01 = self.employee.timesheet_prefill_ids[0]
prefill_02 = self.employee.timesheet_prefill_ids[1]
# We can't know for sure which project was sorted first, so we do the
# below to make sure they are both given a timesheet.
self.assertNotEqual(
prefill_01.project_project_id, prefill_02.project_project_id
)
self.assertIn(prefill_01.project_project_id, projects)
self.assertIn(prefill_02.project_project_id, projects)

sheet = self.env["hr_timesheet.sheet"].create(
{
"employee_id": self.employee.id,
"date_start": "2024-01-01",
"date_end": "2024-01-01",
}
)
self.assertEqual(len(sheet.timesheet_ids), 2)
self.assertNotEqual(
sheet.timesheet_ids[0].project_id, sheet.timesheet_ids[1].project_id
)
self.assertIn(sheet.timesheet_ids[0].project_id, projects)
self.assertIn(sheet.timesheet_ids[1].project_id, projects)

def test_sequenced_repeated_prefills(self):
"""You can repeat and sequence prefills."""
self.employee.timesheet_prefill_ids = [
(0, False, {"project_project_id": self.project_01, "sequence": 1}),
(0, False, {"project_project_id": self.project_02, "sequence": 2}),
(0, False, {"project_project_id": self.project_01, "sequence": 3}),
]

# Sanity check.
self.assertEqual(len(self.employee.project_ids), 3)

sheet = self.env["hr_timesheet.sheet"].create(
{
"employee_id": self.employee.id,
"date_start": "2024-01-01",
"date_end": "2024-01-01",
}
)
self.assertEqual(len(sheet.timesheet_ids), 3)
self.assertEqual(sheet.timesheet_ids[0].project_id, self.project_01)
self.assertEqual(sheet.timesheet_ids[1].project_id, self.project_02)
self.assertEqual(sheet.timesheet_ids[2].project_id, self.project_01)
32 changes: 32 additions & 0 deletions hr_timesheet_sheet_prefill_multi/views/hr_employee_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
SPDX-FileCopyrightText: 2024 Coop IT Easy SC

SPDX-License-Identifier: AGPL-3.0-or-later
-->
<odoo>
<record
id="hr_timesheet_default_analytic_account_view_employee_form"
model="ir.ui.view"
>
<field name="name">hr.employee.view.form</field>
<field name="model">hr.employee</field>
<field
name="inherit_id"
ref="hr_timesheet_sheet_prefill.hr_timesheet_default_analytic_account_view_employee_form"
/>
<field name="arch" type="xml">
<field name="project_ids" position="after">
<field name="timesheet_prefill_ids">
carmenbianca marked this conversation as resolved.
Show resolved Hide resolved
<tree string="Prefill Projects" editable="bottom">
carmenbianca marked this conversation as resolved.
Show resolved Hide resolved
<field name="sequence" widget="handle" />
<field name="project_project_id" />
</tree>
</field>
</field>
<field name="project_ids" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
</odoo>
6 changes: 6 additions & 0 deletions setup/hr_timesheet_sheet_prefill_multi/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Loading