diff --git a/hr_timesheet_sheet_attendance/README.rst b/hr_timesheet_sheet_attendance/README.rst new file mode 100644 index 000000000..9a1b4ae83 --- /dev/null +++ b/hr_timesheet_sheet_attendance/README.rst @@ -0,0 +1,115 @@ +============================= +HR Timesheet Sheet Attendance +============================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:4f73fa862b36263a6f51e2d31ad34be1ddf306ee40934ee3f55f9facc3f2056c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/15.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-15-0/timesheet-15-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=15.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 `_. +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* BizzAppDev + +Contributors +~~~~~~~~~~~~ + +* Ruchir Shukla +* Shruti Singh +* Chirag Parmar +* Naglis Jonaitis +* `Tecnativa `_: + + * 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 `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_timesheet_sheet_attendance/__init__.py b/hr_timesheet_sheet_attendance/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/hr_timesheet_sheet_attendance/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/hr_timesheet_sheet_attendance/__manifest__.py b/hr_timesheet_sheet_attendance/__manifest__.py new file mode 100644 index 000000000..8d91086b3 --- /dev/null +++ b/hr_timesheet_sheet_attendance/__manifest__.py @@ -0,0 +1,15 @@ +{ + "name": "HR Timesheet Sheet Attendance", + "version": "15.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, +} diff --git a/hr_timesheet_sheet_attendance/i18n/hr_timesheet_sheet_attendance.pot b/hr_timesheet_sheet_attendance/i18n/hr_timesheet_sheet_attendance.pot new file mode 100644 index 000000000..c0272f59b --- /dev/null +++ b/hr_timesheet_sheet_attendance/i18n/hr_timesheet_sheet_attendance.pot @@ -0,0 +1,123 @@ +# 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" +"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__display_name +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_timesheet_sheet_attendance +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__id +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__id +msgid "ID" +msgstr "" + +#. module: hr_timesheet_sheet_attendance +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance____last_update +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet____last_update +msgid "Last Modified on" +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 +#: 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 +#: 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 +#: 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 +#: code:addons/hr_timesheet_sheet_attendance/models/hr_attendance.py:0 +#, python-format +msgid "You cannot modify an entry in a confirmed timesheet" +msgstr "" diff --git a/hr_timesheet_sheet_attendance/i18n/it.po b/hr_timesheet_sheet_attendance/i18n/it.po new file mode 100644 index 000000000..9b980bbf8 --- /dev/null +++ b/hr_timesheet_sheet_attendance/i18n/it.po @@ -0,0 +1,132 @@ +# 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-06-22 14:08+0000\n" +"Last-Translator: mymage \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 4.17\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__display_name +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: hr_timesheet_sheet_attendance +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__id +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__id +msgid "ID" +msgstr "ID" + +#. module: hr_timesheet_sheet_attendance +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance____last_update +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. 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 +#: 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 "Scheda 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 +#: 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 +#: 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 +#: 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" diff --git a/hr_timesheet_sheet_attendance/i18n/pt_BR.po b/hr_timesheet_sheet_attendance/i18n/pt_BR.po new file mode 100644 index 000000000..83dd88b52 --- /dev/null +++ b/hr_timesheet_sheet_attendance/i18n/pt_BR.po @@ -0,0 +1,133 @@ +# 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 \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__display_name +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__display_name +msgid "Display Name" +msgstr "Nome exibido" + +#. module: hr_timesheet_sheet_attendance +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance__id +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet__id +msgid "ID" +msgstr "ID" + +#. module: hr_timesheet_sheet_attendance +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_attendance____last_update +#: model:ir.model.fields,field_description:hr_timesheet_sheet_attendance.field_hr_timesheet_sheet____last_update +msgid "Last Modified on" +msgstr "Ultima Modificação em" + +#. 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 +#: 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 +#: 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 +#: 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 +#: 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" diff --git a/hr_timesheet_sheet_attendance/models/__init__.py b/hr_timesheet_sheet_attendance/models/__init__.py new file mode 100644 index 000000000..579390b67 --- /dev/null +++ b/hr_timesheet_sheet_attendance/models/__init__.py @@ -0,0 +1,2 @@ +from . import hr_timesheet_sheet +from . import hr_attendance diff --git a/hr_timesheet_sheet_attendance/models/hr_attendance.py b/hr_timesheet_sheet_attendance/models/hr_attendance.py new file mode 100644 index 000000000..281c9aeff --- /dev/null +++ b/hr_timesheet_sheet_attendance/models/hr_attendance.py @@ -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." + ) + ) diff --git a/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py b/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py new file mode 100644 index 000000000..66a571fb8 --- /dev/null +++ b/hr_timesheet_sheet_attendance/models/hr_timesheet_sheet.py @@ -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 diff --git a/hr_timesheet_sheet_attendance/readme/CONTRIBUTORS.rst b/hr_timesheet_sheet_attendance/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..d86131a65 --- /dev/null +++ b/hr_timesheet_sheet_attendance/readme/CONTRIBUTORS.rst @@ -0,0 +1,7 @@ +* Ruchir Shukla +* Shruti Singh +* Chirag Parmar +* Naglis Jonaitis +* `Tecnativa `_: + + * Ernesto Tejeda diff --git a/hr_timesheet_sheet_attendance/readme/DESCRIPTION.rst b/hr_timesheet_sheet_attendance/readme/DESCRIPTION.rst new file mode 100644 index 000000000..0b1fab8b8 --- /dev/null +++ b/hr_timesheet_sheet_attendance/readme/DESCRIPTION.rst @@ -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. diff --git a/hr_timesheet_sheet_attendance/readme/INSTALL.rst b/hr_timesheet_sheet_attendance/readme/INSTALL.rst new file mode 100644 index 000000000..1f14a7377 --- /dev/null +++ b/hr_timesheet_sheet_attendance/readme/INSTALL.rst @@ -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 diff --git a/hr_timesheet_sheet_attendance/readme/ROADMAP.rst b/hr_timesheet_sheet_attendance/readme/ROADMAP.rst new file mode 100644 index 000000000..874991c9a --- /dev/null +++ b/hr_timesheet_sheet_attendance/readme/ROADMAP.rst @@ -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 diff --git a/hr_timesheet_sheet_attendance/readme/USAGE.rst b/hr_timesheet_sheet_attendance/readme/USAGE.rst new file mode 100644 index 000000000..1f28a7999 --- /dev/null +++ b/hr_timesheet_sheet_attendance/readme/USAGE.rst @@ -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 diff --git a/hr_timesheet_sheet_attendance/static/description/icon.png b/hr_timesheet_sheet_attendance/static/description/icon.png new file mode 100644 index 000000000..8f6c16d77 Binary files /dev/null and b/hr_timesheet_sheet_attendance/static/description/icon.png differ diff --git a/hr_timesheet_sheet_attendance/static/description/index.html b/hr_timesheet_sheet_attendance/static/description/index.html new file mode 100644 index 000000000..ed7e10553 --- /dev/null +++ b/hr_timesheet_sheet_attendance/static/description/index.html @@ -0,0 +1,476 @@ + + + + + + +HR Timesheet Sheet Attendance + + + +
+

HR Timesheet Sheet Attendance

+ + +

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

+

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

+ +
+

Installation

+

This module relies on:

+ +
+
+

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. +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.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • BizzAppDev
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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 project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/hr_timesheet_sheet_attendance/tests/__init__.py b/hr_timesheet_sheet_attendance/tests/__init__.py new file mode 100644 index 000000000..249d9fd6c --- /dev/null +++ b/hr_timesheet_sheet_attendance/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_hr_timesheet_sheet +from . import test_hr_attendance diff --git a/hr_timesheet_sheet_attendance/tests/hr_timesheet_sheet_test_cases.py b/hr_timesheet_sheet_attendance/tests/hr_timesheet_sheet_test_cases.py new file mode 100644 index 000000000..bbe6ca25c --- /dev/null +++ b/hr_timesheet_sheet_attendance/tests/hr_timesheet_sheet_test_cases.py @@ -0,0 +1,80 @@ +import datetime + +from odoo import fields +from odoo.tests.common import TransactionCase + + +class HrTimesheetTestCases(TransactionCase): + def setUp(self): + super(HrTimesheetTestCases, self).setUp() + self.user_id = self._create_user() + self.employee = self._create_employee(self.user_id) + self.timesheet = self._create_timesheet_sheet( + self.employee, datetime.date(2018, 12, 12) + ) + self.project_id = self.env.ref("project.project_project_1") + self.task_1 = self.env.ref("project.project_task_1") + + def _create_user(self): + """Create and return user""" + user_vals = { + "name": "TestUser", + "login": "test", + "password": "test", + "company_id": self.env.ref("base.main_company").id, + "groups_id": [ + ( + 6, + 0, + [ + self.env.ref("base.group_user").id, + self.env.ref("base.group_partner_manager").id, + ], + ) + ], + } + return self.env["res.users"].create(user_vals) + + def _create_employee(self, user): + """Create employee + :param user: record set of res.user + :param return: recordset of hr.employee""" + employee_vals = { + "name": "TestEmployee", + "user_id": self.user_id.id, + "department_id": self.env.ref("hr.dep_rd").id, + "job_id": self.env.ref("hr.job_developer").id, + "category_ids": [(6, 0, [self.env.ref("hr.employee_category_4").id])], + "work_location_id": self.env.ref("hr.work_location_1").id, + "work_email": "test@test.com", + "work_phone": "+3281813700", + } + return self.env["hr.employee"].create(employee_vals) + + def _create_timesheet_sheet(self, 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 self.env["hr_timesheet.sheet"].create(sheet_vals) + + def _create_attendance(self, 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 self.env["hr.attendance"].create(attendance_vals) diff --git a/hr_timesheet_sheet_attendance/tests/test_hr_attendance.py b/hr_timesheet_sheet_attendance/tests/test_hr_attendance.py new file mode 100644 index 000000000..db63dbc65 --- /dev/null +++ b/hr_timesheet_sheet_attendance/tests/test_hr_attendance.py @@ -0,0 +1,73 @@ +import datetime + +from odoo.exceptions import UserError + +from .hr_timesheet_sheet_test_cases import HrTimesheetTestCases + + +class TestHrAttendance(HrTimesheetTestCases): + def setUp(self): + super(TestHrAttendance, self).setUp() + checkInDate = datetime.datetime(2018, 12, 12, 10, 0, 0) + self.attendance_1 = self._create_attendance( + employee=self.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), + } + ) diff --git a/hr_timesheet_sheet_attendance/tests/test_hr_timesheet_sheet.py b/hr_timesheet_sheet_attendance/tests/test_hr_timesheet_sheet.py new file mode 100644 index 000000000..5e89bb739 --- /dev/null +++ b/hr_timesheet_sheet_attendance/tests/test_hr_timesheet_sheet.py @@ -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", + ) diff --git a/hr_timesheet_sheet_attendance/views/hr_attendance_view.xml b/hr_timesheet_sheet_attendance/views/hr_attendance_view.xml new file mode 100644 index 000000000..c5ff0171e --- /dev/null +++ b/hr_timesheet_sheet_attendance/views/hr_attendance_view.xml @@ -0,0 +1,42 @@ + + + + + + view_hr_attendance_filter + hr.attendance + + + + + + + + + + + hr.attendance.form + hr.attendance + + + + + + + + + + + + hr.attendance.tree + hr.attendance + + + + + + + + + + diff --git a/hr_timesheet_sheet_attendance/views/hr_timesheet_sheet_view.xml b/hr_timesheet_sheet_attendance/views/hr_timesheet_sheet_view.xml new file mode 100644 index 000000000..ddf1a0700 --- /dev/null +++ b/hr_timesheet_sheet_attendance/views/hr_timesheet_sheet_view.xml @@ -0,0 +1,109 @@ + + + + + + {'search_default_sheet_id': [active_id],} + Attendances + hr.attendance + + + + + {'search_default_sheet_id': [active_id], 'default_is_timesheet' : 1} + Timesheet Activities + account.analytic.line + + + + + hr_timesheet.sheet.inherit.form + hr_timesheet.sheet + + + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
diff --git a/setup/hr_timesheet_sheet_attendance/odoo/addons/hr_timesheet_sheet_attendance b/setup/hr_timesheet_sheet_attendance/odoo/addons/hr_timesheet_sheet_attendance new file mode 120000 index 000000000..63b69a25c --- /dev/null +++ b/setup/hr_timesheet_sheet_attendance/odoo/addons/hr_timesheet_sheet_attendance @@ -0,0 +1 @@ +../../../../hr_timesheet_sheet_attendance \ No newline at end of file diff --git a/setup/hr_timesheet_sheet_attendance/setup.py b/setup/hr_timesheet_sheet_attendance/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/hr_timesheet_sheet_attendance/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)