Initial commit: OCA Mrp packages (117 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:05 +02:00
commit 277e84fd7a
4403 changed files with 395154 additions and 0 deletions

View file

@ -0,0 +1,47 @@
# HR Timesheet Sheet Attendance
Odoo addon: hr_timesheet_sheet_attendance
## Installation
```bash
pip install odoo-bringout-oca-timesheet-hr_timesheet_sheet_attendance
```
## Dependencies
This addon depends on:
- hr_attendance
- hr_timesheet_sheet
## Manifest Information
- **Name**: HR Timesheet Sheet Attendance
- **Version**: 16.0.1.0.0
- **Category**: Human Resources
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/timesheet](https://github.com/OCA/timesheet) branch 16.0, addon `hr_timesheet_sheet_attendance`.
## License
This package maintains the original AGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Hr_timesheet_sheet_attendance Module - hr_timesheet_sheet_attendance
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for hr_timesheet_sheet_attendance. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,6 @@
# Dependencies
This addon depends on:
- [hr_attendance](../../odoo-bringout-oca-ocb-hr_attendance)
- [hr_timesheet_sheet](../../odoo-bringout-oca-timesheet-hr_timesheet_sheet)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon hr_timesheet_sheet_attendance or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-timesheet-hr_timesheet_sheet_attendance"
# or
uv pip install odoo-bringout-oca-timesheet-hr_timesheet_sheet_attendance"
```

View file

@ -0,0 +1,13 @@
# Models
Detected core models and extensions in hr_timesheet_sheet_attendance.
```mermaid
classDiagram
class hr_attendance
class hr_timesheet_sheet
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: hr_timesheet_sheet_attendance. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon hr_timesheet_sheet_attendance
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,8 @@
# Security
This module does not define custom security rules or access controls beyond Odoo defaults.
Default Odoo security applies:
- Base user access through standard groups
- Model access inherited from dependencies
- No custom row-level security rules

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon hr_timesheet_sheet_attendance
```

View file

@ -0,0 +1,3 @@
# Wizards
This module does not include UI wizards.

View file

@ -0,0 +1,115 @@
=============================
HR Timesheet Sheet Attendance
=============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:09a472a5eff238c13d6c4760a16482560d00674a6460cc4459e9e82dd7964570
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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/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%2Ftimesheet-lightgray.png?logo=github
:target: https://github.com/OCA/timesheet/tree/16.0/hr_timesheet_sheet_attendance
:alt: OCA/timesheet
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/timesheet-16-0/timesheet-16-0-hr_timesheet_sheet_attendance
: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/timesheet&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends the functionality of hr_timesheet_sheet
and help employees to manage their attendance according to timesheet period.
It provide functionality to checkin/checkout directly from timesheet-sheet.
It also help you/management in performace evaluation by displaing
total attendance time and difference of total attendance time and total working time.
**Table of contents**
.. contents::
:local:
Installation
============
This module relies on:
* The OCA module 'HR Timesheet Sheet', and can be downloaded from
Github: https://github.com/OCA/hr-timesheet/tree/15.0/hr_timesheet_sheet
Usage
=====
* Goto Timesheets > My Timesheet Sheets and create a timesheet
* Goto tab Attendances on timesheet form
- You can see there your current status checkin/checkout
- You also can create attendance by clicking on button Check In/Check Out on right side
- You can see your attendance that belongs to current timesheet on left side in same tab
* 'Total Attendance' is total working time based on your attendance
* 'Difference' is the difference betwwen total attandance time and working time (sum(attendace-time) - sum(unit amount in timessheet lines))
* Two smart buttons are present on top-right corner of timesheet form
- First one(with time icon) will take you list of your timesheets (by default filter timesheets related to current timesheet-sheet)
- Second one(labeled as Attendances) will take you to list of your attendances (by default filter ateendances related to current timesheet-sheet)
* It prevents to change in any attendance related to timesheet-sheet that already has submitted
* It also prevents to submit such a timesheet-sheet not having equal number of checkin and checkout
Known issues / Roadmap
======================
By having Check-in/out button in the timesheet, there could perhaps be a case where the user does two clicks in a fast way, then the check-in and check-out times are the same and the attendance gets blocked as there is an Odoo standard check which verifies that the attendance check-in time is strictly minor than the check-out time
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/timesheet/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/timesheet/issues/new?body=module:%20hr_timesheet_sheet_attendance%0Aversion:%2016.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
~~~~~~~
* BizzAppDev
Contributors
~~~~~~~~~~~~
* Ruchir Shukla <ruchir@bizzappdev.com>
* Shruti Singh <shruti.singh@bizzappdev.com>
* Chirag Parmar <chirag.parmar@bizzappdev.com>
* Naglis Jonaitis <naglis@versada.eu>
* `Tecnativa <https://www.tecnativa.com>`_:
* Ernesto Tejeda
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/timesheet <https://github.com/OCA/timesheet/tree/16.0/hr_timesheet_sheet_attendance>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,15 @@
{
"name": "HR Timesheet Sheet Attendance",
"version": "16.0.1.0.0",
"category": "Human Resources",
"sequence": 80,
"license": "AGPL-3",
"author": "BizzAppDev, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/timesheet",
"depends": ["hr_attendance", "hr_timesheet_sheet"],
"data": [
"views/hr_timesheet_sheet_view.xml",
"views/hr_attendance_view.xml",
],
"installable": True,
}

View file

@ -0,0 +1,109 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_timesheet_sheet_attendance
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.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_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_attendance
msgid "Attendance"
msgstr "Prisutnost"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_count
msgid "Attendance Count"
msgstr "Broj prisustva"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendances_ids
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Attendances"
msgstr "Prisutnosti"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check In"
msgstr "Prijava"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check Out"
msgstr "Odjava"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_state
msgid "Current Status"
msgstr "Trenutni status"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_difference
msgid "Difference"
msgstr "Razlika"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__sheet_id
msgid "Sheet"
msgstr "List"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py:0
#, python-format
msgid ""
"The timesheet cannot be validated as it does not contain an equal number of "
"sign ins and sign outs."
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Timesheet"
msgstr "Šihtarica"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_activities
msgid "Timesheet Activities"
msgstr "Aktivnosti u šihtaricama"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_timesheet_sheet
msgid "Timesheet Sheet"
msgstr "Vremenski listovi"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_attendance
msgid "Total Attendance"
msgstr "Ukupno prisustvo"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance date outside the current timesheet dates."
msgstr ""
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance in a submitted timesheet. Ask your manager "
"to reset it before adding attendance."
msgstr ""
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid "You cannot modify an entry in a confirmed timesheet"
msgstr "Ne možete modificirati unos u potvrđenom listu radnih listova"

View file

@ -0,0 +1,119 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_timesheet_sheet_attendance
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-17 09:59+0000\n"
"PO-Revision-Date: 2024-04-17 09:59+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_attendance
msgid "Attendance"
msgstr "Asistencia"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_count
msgid "Attendance Count"
msgstr "Número de asistencias"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendances_ids
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Attendances"
msgstr "Asistencias"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check In"
msgstr "Entrada"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check Out"
msgstr "Salida"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_state
msgid "Current Status"
msgstr "Estado Actual"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_difference
msgid "Difference"
msgstr "Diferencia"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__sheet_id
msgid "Sheet"
msgstr "Hoja de Servicios"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py:0
#, python-format
msgid ""
"The timesheet cannot be validated as it does not contain an equal number of "
"sign ins and sign outs."
msgstr ""
"La hoja de servicios no puede ser validada ya que no contiene el mismo "
"número de entradas y salidas."
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Timesheet"
msgstr "Hoja de Servicios"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_activities
msgid "Timesheet Activities"
msgstr "Actividades de Hoja de Servicios"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_timesheet_sheet
msgid "Timesheet Sheet"
msgstr "Hoja de Servicios"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_attendance
msgid "Total Attendance"
msgstr "Asistencia Total"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance date outside the current timesheet dates."
msgstr ""
"No puedes introducir una fecha de asistencia fuera de las fechas para la "
"hoja de servicios actual."
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance in a submitted timesheet. Ask your manager "
"to reset it before adding attendance."
msgstr ""
"No puedes introducir una asistencia en una hoja de servicios enviada a "
"revisión. Pídale a su responsable que la restablezca antes de introducir la "
"asistencia."
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid "You cannot modify an entry in a confirmed timesheet"
msgstr "No puedes modificar una entrada para una hoja de servicios confirmada"

View file

@ -0,0 +1,109 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_timesheet_sheet_attendance
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.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_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_attendance
msgid "Attendance"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_count
msgid "Attendance Count"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendances_ids
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Attendances"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check In"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check Out"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_state
msgid "Current Status"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_difference
msgid "Difference"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__sheet_id
msgid "Sheet"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py:0
#, python-format
msgid ""
"The timesheet cannot be validated as it does not contain an equal number of "
"sign ins and sign outs."
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Timesheet"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_activities
msgid "Timesheet Activities"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_timesheet_sheet
msgid "Timesheet Sheet"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_attendance
msgid "Total Attendance"
msgstr ""
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance date outside the current timesheet dates."
msgstr ""
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance in a submitted timesheet. Ask your manager "
"to reset it before adding attendance."
msgstr ""
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid "You cannot modify an entry in a confirmed timesheet"
msgstr ""

View file

@ -0,0 +1,127 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_timesheet_sheet_attendance
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-30 10:44+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.10.4\n"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_attendance
msgid "Attendance"
msgstr "Presenza"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_count
msgid "Attendance Count"
msgstr "Conteggio presenze"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendances_ids
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Attendances"
msgstr "Presenti"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check In"
msgstr "Check-in"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check Out"
msgstr "Check-out"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_state
msgid "Current Status"
msgstr "Stato attuale"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_difference
msgid "Difference"
msgstr "Differenza"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__sheet_id
msgid "Sheet"
msgstr "Prospetto"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py:0
#, python-format
msgid ""
"The timesheet cannot be validated as it does not contain an equal number of "
"sign ins and sign outs."
msgstr ""
"Il fogli ore non può essere validato perché non contiene un numero uguale di "
"entrate e uscite."
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Timesheet"
msgstr "Foglio ore"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_activities
msgid "Timesheet Activities"
msgstr "Attività fogli oore"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_timesheet_sheet
msgid "Timesheet Sheet"
msgstr "Prospetto foglio ore"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_attendance
msgid "Total Attendance"
msgstr "Totale presenze"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance date outside the current timesheet dates."
msgstr ""
"Non si può inserire una presenza con una data al di fuori delle date del "
"fogli ore attuale."
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance in a submitted timesheet. Ask your manager "
"to reset it before adding attendance."
msgstr ""
"Non si può inserire una presenza in un foglio ore inviato. Richiedere al "
"responsabile di resettarlo prima di aggiungere la presenza."
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid "You cannot modify an entry in a confirmed timesheet"
msgstr "Non si può modificare una registrazione in un fogli ore confermato"
#~ msgid "Display Name"
#~ msgstr "Nome visualizzato"
#~ msgid "ID"
#~ msgstr "ID"
#~ msgid "Last Modified on"
#~ msgstr "Ultima modifica il"

View file

@ -0,0 +1,128 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * hr_timesheet_sheet_attendance
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-03-14 12:22+0000\n"
"Last-Translator: Douglas Custódio <douglascstd@yahoo.com>\n"
"Language-Team: none\n"
"Language: pt_BR\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 4.14.1\n"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_attendance
msgid "Attendance"
msgstr "Presença"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_count
msgid "Attendance Count"
msgstr "Contagem de Presença"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendances_ids
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Attendances"
msgstr "Presenças"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check In"
msgstr "Check-in"
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Check Out"
msgstr "Check-out"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__attendance_state
msgid "Current Status"
msgstr "Situação Atual"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_difference
msgid "Difference"
msgstr "Diferença"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__sheet_id
msgid "Sheet"
msgstr "Planilha"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py:0
#, python-format
msgid ""
"The timesheet cannot be validated as it does not contain an equal number of "
"sign ins and sign outs."
msgstr ""
"A planilha de horas não pode ser validado como não contém um numero igual de "
"entradas e saídas."
#. module: hr_timesheet_sheet_attendance
#: model_terms:ir.ui.view,arch_db:hr_timesheet_sheet_attendance.hr_timesheet_sheet_form
msgid "Timesheet"
msgstr "Apontamento de hora"
#. module: hr_timesheet_sheet_attendance
#: model:ir.actions.act_window,name:hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_activities
msgid "Timesheet Activities"
msgstr "Atividades do apontamento de hora"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model,name:hr_timesheet_sheet_attendance.model_hr_timesheet_sheet
msgid "Timesheet Sheet"
msgstr "Planilha de horas"
#. module: hr_timesheet_sheet_attendance
#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__total_attendance
msgid "Total Attendance"
msgstr "Total de Presença"
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance date outside the current timesheet dates."
msgstr ""
"Você não pode inserir uma data de presença fora das atuais datas de "
"apontamento de horas."
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid ""
"You can not enter an attendance in a submitted timesheet. Ask your manager "
"to reset it before adding attendance."
msgstr ""
"Você não pode inserir uma presença em um apontamento de horas enviado. "
"Solicite ao seu gerente para reinicia-lo antes de adicionar presenças."
#. module: hr_timesheet_sheet_attendance
#. odoo-python
#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0
#, python-format
msgid "You cannot modify an entry in a confirmed timesheet"
msgstr ""
"Você não pode modificar um lançamento em um apontamento de horas confirmado"
#~ msgid "Display Name"
#~ msgstr "Nome exibido"
#~ msgid "ID"
#~ msgstr "ID"
#~ msgid "Last Modified on"
#~ msgstr "Ultima Modificação em"

View file

@ -0,0 +1,2 @@
from . import hr_timesheet_sheet
from . import hr_attendance

View file

@ -0,0 +1,103 @@
import pytz
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class HrAttendance(models.Model):
_inherit = "hr.attendance"
def _get_attendance_employee_tz(self, date=None):
"""Convert date according to timezone of user
:param date: datetime.datetime.
:return: datetime.date with applied timezone or False"""
tz = False
if self.employee_id.user_id:
tz = self.employee_id.user_id.partner_id.tz
if not date:
return False
time_zone = pytz.timezone(tz or "UTC")
attendance_tz_dt = pytz.UTC.localize(date)
attendance_tz_dt = attendance_tz_dt.astimezone(time_zone)
return attendance_tz_dt.date()
def _get_timesheet_sheet(self):
"""Find and return current timesheet-sheet
:return: recordset of hr_timesheet.sheet or False"""
sheet_obj = self.env["hr_timesheet.sheet"]
check_in = False
if self.check_in:
check_in = self._get_attendance_employee_tz(date=self.check_in)
domain = [("employee_id", "=", self.employee_id.id)]
if check_in:
domain += [("date_start", "<=", check_in), ("date_end", ">=", check_in)]
sheet_ids = sheet_obj.search(domain, limit=1)
return sheet_ids[:1] or False
@api.depends("employee_id", "check_in", "check_out")
def _compute_sheet_id(self):
"""Find and set current timesheet-sheet in
current attendance record"""
for attendance in self:
attendance.sheet_id = attendance._get_timesheet_sheet()
sheet_id = fields.Many2one(
comodel_name="hr_timesheet.sheet",
compute="_compute_sheet_id",
string="Sheet",
store=True,
)
def _check_timesheet_state(self):
"""Check and raise error if current sheet not in draftstate"""
if self._context.get("allow_modify_confirmed_sheet", False):
return
if self.sheet_id and self.sheet_id.state != "draft":
raise UserError(_("You cannot modify an entry in a confirmed timesheet"))
def unlink(self):
# Restrict to delete attendance from confirmed timesheet-sheet
for attendance in self:
attendance._check_timesheet_state()
return super(HrAttendance, self).unlink()
@api.constrains("check_in", "check_out")
def _check_timesheet(self):
"""- Restrict to create attendance in confirmed timesheet-sheet
- Restrict to add attendance date outside the current
timesheet dates"""
timesheet = self.sheet_id
if not timesheet:
return
if timesheet and timesheet.state != "draft":
raise UserError(
_(
"You can not enter an attendance in a submitted timesheet. "
+ "Ask your manager to reset it before adding attendance."
)
)
else:
checkin_tz_date = self._get_attendance_employee_tz(date=self.check_in)
checkout_tz_date = self._get_attendance_employee_tz(date=self.check_out)
if (
(
timesheet.date_start > checkin_tz_date
or timesheet.date_end < checkin_tz_date
)
or checkout_tz_date
and (
timesheet.date_start > checkout_tz_date
or timesheet.date_end < checkout_tz_date
)
):
raise UserError(
_(
"You can not enter an attendance date "
+ "outside the current timesheet dates."
)
)

View file

@ -0,0 +1,107 @@
from datetime import datetime
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class HrTimesheetSheet(models.Model):
_inherit = "hr_timesheet.sheet"
def _compute_attendance_count(self):
"""Compute total number of attendance records
linked to current timesheet"""
for attendances in self:
attendances.attendance_count = len(attendances.attendances_ids)
@api.depends(
"timesheet_ids",
"timesheet_ids.unit_amount",
"attendances_ids",
"attendances_ids.check_in",
"attendances_ids.check_out",
"attendances_ids.employee_id",
)
def _compute_attendance_time(self):
"""Compute total attendance time and
difference in total attendance-time
and timesheet-entry"""
current_date = datetime.now()
for sheet in self:
atte_without_checkout = sheet.attendances_ids.filtered(
lambda attendance: not attendance.check_out
)
atte_with_checkout = sheet.attendances_ids - atte_without_checkout
total_time = sum(atte_with_checkout.mapped("worked_hours"))
for attendance in atte_without_checkout:
delta = current_date - attendance.check_in
total_time += delta.total_seconds() / 3600.0
sheet.total_attendance = total_time
# calculate total difference
total_working_time = sum(sheet.mapped("timesheet_ids.unit_amount"))
sheet.total_difference = total_time - total_working_time
total_attendance = fields.Float(
compute="_compute_attendance_time",
)
total_difference = fields.Float(
compute="_compute_attendance_time",
string="Difference",
)
attendances_ids = fields.One2many(
comodel_name="hr.attendance", inverse_name="sheet_id", string="Attendances"
)
attendance_state = fields.Selection(
related="employee_id.attendance_state",
related_sudo=True,
string="Current Status",
)
attendance_count = fields.Integer(compute="_compute_attendance_count")
def attendance_action_change(self):
"""Call attendance_action_change to
perform Check In/Check Out action
Returns last attendance record"""
return self.employee_id._attendance_action_change()
def action_timesheet_confirm(self):
self.check_employee_attendance_state()
return super(HrTimesheetSheet, self).action_timesheet_confirm()
def check_employee_attendance_state(self):
"""Restrict to submit sheet contains
attendance without checkout"""
for sheet in self:
ids_not_checkout = sheet.attendances_ids.filtered(
lambda att: att.check_in and not att.check_out
)
if not ids_not_checkout:
continue
raise UserError(
_(
"The timesheet cannot be validated as it does "
+ "not contain an equal number of sign ins and sign outs."
)
)
@api.model
def create(self, vals):
res = super(HrTimesheetSheet, self).create(vals)
attendances = self.env["hr.attendance"].search(
[
("employee_id", "=", res.employee_id.id),
("sheet_id", "=", False),
("check_in", ">=", res.date_start),
("check_in", "<=", res.date_end),
"|",
("check_out", "=", False),
"&",
("check_out", ">=", res.date_start),
("check_out", "<=", res.date_end),
]
)
attendances._compute_sheet_id()
return res

View file

@ -0,0 +1,7 @@
* Ruchir Shukla <ruchir@bizzappdev.com>
* Shruti Singh <shruti.singh@bizzappdev.com>
* Chirag Parmar <chirag.parmar@bizzappdev.com>
* Naglis Jonaitis <naglis@versada.eu>
* `Tecnativa <https://www.tecnativa.com>`_:
* Ernesto Tejeda

View file

@ -0,0 +1,5 @@
This module extends the functionality of hr_timesheet_sheet
and help employees to manage their attendance according to timesheet period.
It provide functionality to checkin/checkout directly from timesheet-sheet.
It also help you/management in performace evaluation by displaing
total attendance time and difference of total attendance time and total working time.

View file

@ -0,0 +1,4 @@
This module relies on:
* The OCA module 'HR Timesheet Sheet', and can be downloaded from
Github: https://github.com/OCA/hr-timesheet/tree/15.0/hr_timesheet_sheet

View file

@ -0,0 +1 @@
By having Check-in/out button in the timesheet, there could perhaps be a case where the user does two clicks in a fast way, then the check-in and check-out times are the same and the attendance gets blocked as there is an Odoo standard check which verifies that the attendance check-in time is strictly minor than the check-out time

View file

@ -0,0 +1,12 @@
* Goto Timesheets > My Timesheet Sheets and create a timesheet
* Goto tab Attendances on timesheet form
- You can see there your current status checkin/checkout
- You also can create attendance by clicking on button Check In/Check Out on right side
- You can see your attendance that belongs to current timesheet on left side in same tab
* 'Total Attendance' is total working time based on your attendance
* 'Difference' is the difference betwwen total attandance time and working time (sum(attendace-time) - sum(unit amount in timessheet lines))
* Two smart buttons are present on top-right corner of timesheet form
- First one(with time icon) will take you list of your timesheets (by default filter timesheets related to current timesheet-sheet)
- Second one(labeled as Attendances) will take you to list of your attendances (by default filter ateendances related to current timesheet-sheet)
* It prevents to change in any attendance related to timesheet-sheet that already has submitted
* It also prevents to submit such a timesheet-sheet not having equal number of checkin and checkout

View file

@ -0,0 +1,476 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>HR Timesheet Sheet Attendance</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="hr-timesheet-sheet-attendance">
<h1 class="title">HR Timesheet Sheet Attendance</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:09a472a5eff238c13d6c4760a16482560d00674a6460cc4459e9e82dd7964570
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/timesheet/tree/16.0/hr_timesheet_sheet_attendance"><img alt="OCA/timesheet" src="https://img.shields.io/badge/github-OCA%2Ftimesheet-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/timesheet-16-0/timesheet-16-0-hr_timesheet_sheet_attendance"><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/timesheet&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module extends the functionality of hr_timesheet_sheet
and help employees to manage their attendance according to timesheet period.
It provide functionality to checkin/checkout directly from timesheet-sheet.
It also help you/management in performace evaluation by displaing
total attendance time and difference of total attendance time and total working time.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-3">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>This module relies on:</p>
<ul class="simple">
<li>The OCA module HR Timesheet Sheet, and can be downloaded from
Github: <a class="reference external" href="https://github.com/OCA/hr-timesheet/tree/15.0/hr_timesheet_sheet">https://github.com/OCA/hr-timesheet/tree/15.0/hr_timesheet_sheet</a></li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<ul class="simple">
<li>Goto Timesheets &gt; My Timesheet Sheets and create a timesheet</li>
<li><dl class="first docutils">
<dt>Goto tab Attendances on timesheet form</dt>
<dd><ul class="first last">
<li>You can see there your current status checkin/checkout</li>
<li>You also can create attendance by clicking on button Check In/Check Out on right side</li>
<li>You can see your attendance that belongs to current timesheet on left side in same tab</li>
</ul>
</dd>
</dl>
</li>
<li>Total Attendance is total working time based on your attendance</li>
<li>Difference is the difference betwwen total attandance time and working time (sum(attendace-time) - sum(unit amount in timessheet lines))</li>
<li><dl class="first docutils">
<dt>Two smart buttons are present on top-right corner of timesheet form</dt>
<dd><ul class="first last">
<li>First one(with time icon) will take you list of your timesheets (by default filter timesheets related to current timesheet-sheet)</li>
<li>Second one(labeled as Attendances) will take you to list of your attendances (by default filter ateendances related to current timesheet-sheet)</li>
</ul>
</dd>
</dl>
</li>
<li>It prevents to change in any attendance related to timesheet-sheet that already has submitted</li>
<li>It also prevents to submit such a timesheet-sheet not having equal number of checkin and checkout</li>
</ul>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
<p>By having Check-in/out button in the timesheet, there could perhaps be a case where the user does two clicks in a fast way, then the check-in and check-out times are the same and the attendance gets blocked as there is an Odoo standard check which verifies that the attendance check-in time is strictly minor than the check-out time</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/timesheet/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/timesheet/issues/new?body=module:%20hr_timesheet_sheet_attendance%0Aversion:%2016.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">
<h1><a class="toc-backref" href="#toc-entry-5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-6">Authors</a></h2>
<ul class="simple">
<li>BizzAppDev</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<ul class="simple">
<li>Ruchir Shukla &lt;<a class="reference external" href="mailto:ruchir&#64;bizzappdev.com">ruchir&#64;bizzappdev.com</a>&gt;</li>
<li>Shruti Singh &lt;<a class="reference external" href="mailto:shruti.singh&#64;bizzappdev.com">shruti.singh&#64;bizzappdev.com</a>&gt;</li>
<li>Chirag Parmar &lt;<a class="reference external" href="mailto:chirag.parmar&#64;bizzappdev.com">chirag.parmar&#64;bizzappdev.com</a>&gt;</li>
<li>Naglis Jonaitis &lt;<a class="reference external" href="mailto:naglis&#64;versada.eu">naglis&#64;versada.eu</a>&gt;</li>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Ernesto Tejeda</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">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" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/timesheet/tree/16.0/hr_timesheet_sheet_attendance">OCA/timesheet</a> project on GitHub.</p>
<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>
</body>
</html>

View file

@ -0,0 +1,2 @@
from . import test_hr_timesheet_sheet
from . import test_hr_attendance

View file

@ -0,0 +1,85 @@
import datetime
from odoo import fields
from odoo.tests.common import TransactionCase
class HrTimesheetTestCases(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user_id = cls._create_user()
cls.employee = cls._create_employee(cls.user_id)
cls.timesheet = cls._create_timesheet_sheet(
cls.employee, datetime.date(2018, 12, 12)
)
cls.project_id = cls.env.ref("project.project_project_1")
cls.task_1 = cls.env.ref("project.project_1_task_9")
@classmethod
def _create_user(cls):
"""Create and return user"""
user_vals = {
"name": "TestUser",
"login": "test",
"password": "test",
"company_id": cls.env.ref("base.main_company").id,
"groups_id": [
(
6,
0,
[
cls.env.ref("base.group_user").id,
cls.env.ref("base.group_partner_manager").id,
],
)
],
}
return cls.env["res.users"].create(user_vals)
@classmethod
def _create_employee(cls, user):
"""Create employee
:param user: record set of res.user
:param return: recordset of hr.employee"""
employee_vals = {
"name": "TestEmployee",
"user_id": cls.user_id.id,
"department_id": cls.env.ref("hr.dep_rd").id,
"job_id": cls.env.ref("hr.job_developer").id,
"category_ids": [(6, 0, [cls.env.ref("hr.employee_category_4").id])],
"work_location_id": cls.env.ref("hr.work_location_1").id,
"work_email": "test@test.com",
"work_phone": "+3281813700",
}
return cls.env["hr.employee"].create(employee_vals)
@classmethod
def _create_timesheet_sheet(cls, employee, date=None):
"""Create employee
:param employee: record set of hr.employee
:param str date: date
:param return: recordset of hr_timesheet.sheet"""
if not date:
date = fields.Date.today()
sheet_vals = {
"employee_id": employee.id,
"date_start": date,
"date_end": date,
}
return cls.env["hr_timesheet.sheet"].create(sheet_vals)
@classmethod
def _create_attendance(cls, employee, checkIn=None, checkOut=None):
"""Create employee
:param employee: record set of hr.employee
:param str checkIn: datetime
:param str checkOut: datetime
:param return: recordset of hr.attendance"""
attendance_vals = {
"employee_id": employee.id,
"check_in": checkIn,
}
if checkOut:
attendance_vals.update({"check_out": checkOut})
return cls.env["hr.attendance"].create(attendance_vals)

View file

@ -0,0 +1,74 @@
import datetime
from odoo.exceptions import UserError
from .hr_timesheet_sheet_test_cases import HrTimesheetTestCases
class TestHrAttendance(HrTimesheetTestCases):
@classmethod
def setUpClass(cls):
super().setUpClass()
checkInDate = datetime.datetime(2018, 12, 12, 10, 0, 0)
cls.attendance_1 = cls._create_attendance(
employee=cls.employee,
checkIn=checkInDate,
)
def test_00_compute_sheet_id(self):
# check sheet_id in attendances
self.attendance_1._compute_sheet_id()
self.assertEqual(
self.timesheet,
self.attendance_1.sheet_id,
"Error while computing sheet_id on attendance.\
\nMethod: _compute_sheet_id",
)
def test_01_test_timezone_conversion(self):
# check for _get_attendance_employee_tz
self.user_id.tz = "Etc/GMT+12"
date = datetime.datetime(2018, 12, 12, 10, 0, 0)
attDate = self.attendance_1._get_attendance_employee_tz(date=date)
self.assertEqual(
attDate,
datetime.date(2018, 12, 11),
"Error while converting date/datetime in user's timezone.\
\nMethod: _get_attendance_employee_tz",
)
def test_02_check_timesheet_confirm(self):
# check check_in & check_out equal or not
with self.assertRaises(UserError):
self.timesheet.action_timesheet_confirm()
# unlink attendance from confirmed timesheet
self.attendance_1.check_out = datetime.datetime(2018, 12, 12, 13, 0, 0)
self.timesheet.action_timesheet_confirm()
with self.assertRaises(UserError):
self.attendance_1.unlink()
# create attendance in confirmed timesheet
with self.assertRaises(UserError):
checkInDate = datetime.datetime(2018, 12, 12, 13, 35, 0)
self._create_attendance(
employee=self.employee,
checkIn=checkInDate,
)
# modify attendance in confirmed timesheet
with self.assertRaises(UserError):
self.attendance_1.write(
{
"check_in": datetime.datetime(2018, 12, 12, 14, 0, 0),
}
)
def test_03_check_timesheet(self):
# check when create attendance out_side the current timesheet date
with self.assertRaises(UserError):
self.attendance_1.write(
{
"check_out": datetime.datetime(2018, 12, 16, 17, 0, 0),
}
)

View file

@ -0,0 +1,143 @@
import datetime
from odoo.exceptions import UserError
from .hr_timesheet_sheet_test_cases import HrTimesheetTestCases
class TestHrTimesheetSheet(HrTimesheetTestCases):
def test_00_check_timesheet_compute_old_attendance(self):
"""sheet_id should compute for attendaces which
were created before creation of timesheet"""
checkInDate = datetime.datetime(2018, 11, 12, 10, 0, 0)
self._create_attendance(
employee=self.employee,
checkIn=checkInDate,
)
time_sheet = self._create_timesheet_sheet(
self.employee, datetime.date(2018, 11, 12)
)
self.assertEqual(
time_sheet.attendance_count,
1,
"Error while computing sheet_id of already created attendances.\
\nMethod: create",
)
def test_01_compute_total_time_and_difference(self):
"""Check for time difference, total attendance time
and attendance count"""
# Attendance - 1
checkInDate = datetime.datetime(2018, 12, 12, 10, 0, 0)
checkOutDate = datetime.datetime(2018, 12, 12, 12, 0, 0)
self._create_attendance(
employee=self.employee,
checkIn=checkInDate,
checkOut=checkOutDate,
)
self.assertEqual(
self.timesheet.attendance_count,
1,
"Error while computing total attendance count.\
\nMethod: _compute_attendance_count",
)
self.assertEqual(
self.timesheet.total_attendance,
2.0,
"Error while computing total working time.\
\nMethod: _compute_attendance_time",
)
self.assertEqual(
self.timesheet.total_difference,
2.0,
"Error while computing total total difference.\
\nMethod: _compute_attendance_time",
)
# Attendance - 2
checkInDate = datetime.datetime(2018, 12, 12, 13, 0, 0)
checkOutDate = datetime.datetime(2018, 12, 12, 14, 0, 0)
self._create_attendance(
employee=self.employee,
checkIn=checkInDate,
checkOut=checkOutDate,
)
self.timesheet._compute_attendance_count()
self.assertEqual(
self.timesheet.attendance_count,
2,
"Error while computing total attendance count.\
\nMethod: _compute_attendance_count",
)
self.assertEqual(
self.timesheet.total_attendance,
3.0,
"Error while computing total working time.\
\nMethod: _compute_attendance_time",
)
self.assertEqual(
self.timesheet.total_difference,
3.0,
"Error while computing total total difference.\
\nMethod: _compute_attendance_time",
)
# Create timesheet lines
self.timesheet.timesheet_ids = [
(
0,
0,
{
"employee_id": self.employee.id,
"date": datetime.date(2018, 12, 12),
"project_id": self.project_id.id,
"task_id": self.task_1.id,
"name": "testing",
"unit_amount": 1.0,
},
)
]
self.assertEqual(
self.timesheet.total_difference,
2.0,
"Error while computing total total difference.\
\nMethod: _compute_attendance_time",
)
# # Attendance - 3
checkInDate = datetime.datetime(2018, 12, 12, 16, 0, 0)
attendance_3 = self._create_attendance(
employee=self.employee,
checkIn=checkInDate,
)
with self.assertRaises(UserError):
self.timesheet.action_timesheet_confirm()
attendance_3.check_out = datetime.datetime(2018, 12, 12, 17, 0, 0)
self.timesheet.action_timesheet_confirm()
self.assertEqual(
self.timesheet.state,
"confirm",
"Error while confirming timesheet.\
\nMethod: action_timesheet_confirm",
)
def test_03_sighin_sighout(self):
"""test Check In/Check Out button on timesheet-sheet"""
time_sheet = self._create_timesheet_sheet(self.employee)
time_sheet.attendance_action_change()
self.assertNotEqual(
time_sheet.attendances_ids.filtered(lambda att: not att.check_out).ids,
[],
"Error while sighin using button on timesheet.\
\nMethod: attendance_action_change",
)
time_sheet.attendance_action_change()
self.assertEqual(
time_sheet.attendances_ids.filtered(lambda att: not att.check_out).ids,
[],
"Error while signout using button on timesheet.\
\nMethod: attendance_action_change",
)

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- hr_attendance inherited filter view-->
<record id="hr_attendance_view_filter" model="ir.ui.view">
<field name="name">view_hr_attendance_filter</field>
<field name="model">hr.attendance</field>
<field name="inherit_id" ref="hr_attendance.hr_attendance_view_filter" />
<field name="arch" type="xml">
<field name="employee_id" position="after">
<field name="sheet_id" />
</field>
</field>
</record>
<!-- hr_attendance inherited form view-->
<record id="hr_attendance_view_form" model="ir.ui.view">
<field name="name">hr.attendance.form</field>
<field name="model">hr.attendance</field>
<field name="inherit_id" ref="hr_attendance.hr_attendance_view_form" />
<field name="arch" type="xml">
<field name="check_out" position="after">
<field name="worked_hours" />
<field name="sheet_id" />
</field>
</field>
</record>
<!-- hr_attendance inherited tree view-->
<record id="view_attendance_tree" model="ir.ui.view">
<field name="name">hr.attendance.tree</field>
<field name="model">hr.attendance</field>
<field name="inherit_id" ref="hr_attendance.view_attendance_tree" />
<field name="arch" type="xml">
<field name="check_out" position="after">
<field name="worked_hours" />
<field name="sheet_id" />
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!-- create action for Attendances view-->
<record
id="hr_timesheet_sheet_action_sheet_attendance"
model="ir.actions.act_window"
>
<field name="context">{'search_default_sheet_id': [active_id],}</field>
<field name="name">Attendances</field>
<field name="res_model">hr.attendance</field>
</record>
<!-- create action for Timesheet view-->
<record
id="hr_timesheet_sheet_action_sheet_activities"
model="ir.actions.act_window"
>
<field
name="context"
>{'search_default_sheet_id': [active_id], 'default_is_timesheet' : 1}</field>
<field name="name">Timesheet Activities</field>
<field name="res_model">account.analytic.line</field>
</record>
<!-- hr_timesheet_sheet inherited view-->
<record id="hr_timesheet_sheet_form" model="ir.ui.view">
<field name="name">hr_timesheet.sheet.inherit.form</field>
<field name="model">hr_timesheet.sheet</field>
<field name="inherit_id" ref="hr_timesheet_sheet.hr_timesheet_sheet_form" />
<field name="arch" type="xml">
<xpath expr="//sheet/div[hasclass('oe_title')]" position="before">
<div class="oe_button_box" name="button_box">
<button
type="action"
name="%(hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_activities)d"
class="oe_stat_button"
icon="fa-clock-o"
>
<field
name="total_time"
widget="float_time"
string="Timesheet"
/>
</button>
<button
type="action"
groups="hr_attendance.group_hr_attendance_user"
class="oe_stat_button oe_right"
icon="fa-users"
name="%(hr_timesheet_sheet_attendance.hr_timesheet_sheet_action_sheet_attendance)d"
>
<field
name="attendance_count"
widget="statinfo"
string="Attendances"
/>
</button>
</div>
</xpath>
<xpath expr="//sheet/group" position="inside">
<group groups="hr_attendance.group_hr_attendance">
<field name="total_attendance" widget="float_time" />
<field name="total_difference" widget="float_time" />
</group>
</xpath>
<xpath expr="//sheet/notebook" position="inside">
<page string="Attendances" groups="hr_attendance.group_hr_attendance">
<group colspan="4">
<group>
<label for="attendance_state" />
<div>
<field name="attendance_state" />
<button
name="attendance_action_change"
attrs="{'invisible': [('attendance_state', '=', 'checked_in')]}"
type="object"
string="Check In"
style="margin-left: 20px"
/>
<button
name="attendance_action_change"
attrs="{'invisible': ['|', ('attendance_state','=',False), ('attendance_state', '=', 'checked_out')]}"
type="object"
string="Check Out"
style="margin-left: 20px"
/>
</div>
</group>
<field
name="attendances_ids"
nolabel="1"
options="{'no_create': True, 'no_open': True}"
context="{'default_employee_id': employee_id}"
readonly="1"
>
<tree>
<field name="check_in" />
<field name="check_out" />
<field invisible="1" name="employee_id" />
</tree>
</field>
</group>
</page>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,43 @@
[project]
name = "odoo-bringout-oca-timesheet-hr_timesheet_sheet_attendance"
version = "16.0.0"
description = "HR Timesheet Sheet Attendance - Odoo addon"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-timesheet-hr_attendance>=16.0.0",
"odoo-bringout-oca-timesheet-hr_timesheet_sheet>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["hr_timesheet_sheet_attendance"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]