From b02847e79210f3927cc2733692cfbe3ef3a1b66d Mon Sep 17 00:00:00 2001 From: Andhitia Rama Date: Sun, 27 May 2018 22:51:39 +0700 Subject: [PATCH] [8.0.1.0.0] hr_timesheet_attendance_schedule --- hr_timesheet_attendance_schedule/README.rst | 39 ++++ hr_timesheet_attendance_schedule/__init__.py | 5 + .../__openerp__.py | 24 +++ .../data/base_action_rule_data.xml | 17 ++ .../data/ir_actions_server_data.xml | 21 ++ .../data/ir_filters_data.xml | 16 ++ .../models/__init__.py | 9 + .../models/hr_attendance.py | 38 ++++ .../hr_timesheet_attendance_schedule.py | 185 ++++++++++++++++++ .../models/hr_timesheet_sheet.py | 66 +++++++ .../models/res_company.py | 20 ++ .../models/res_config.py | 18 ++ .../security/ir.model.access.csv | 3 + .../static/description/icon.png | Bin 0 -> 14784 bytes .../hr_attendance_config_setting_views.xml | 31 +++ ...hr_timesheet_attendance_schedule_views.xml | 97 +++++++++ .../views/hr_timesheet_sheet_views.xml | 62 ++++++ 17 files changed, 651 insertions(+) create mode 100644 hr_timesheet_attendance_schedule/README.rst create mode 100644 hr_timesheet_attendance_schedule/__init__.py create mode 100644 hr_timesheet_attendance_schedule/__openerp__.py create mode 100644 hr_timesheet_attendance_schedule/data/base_action_rule_data.xml create mode 100644 hr_timesheet_attendance_schedule/data/ir_actions_server_data.xml create mode 100644 hr_timesheet_attendance_schedule/data/ir_filters_data.xml create mode 100644 hr_timesheet_attendance_schedule/models/__init__.py create mode 100644 hr_timesheet_attendance_schedule/models/hr_attendance.py create mode 100644 hr_timesheet_attendance_schedule/models/hr_timesheet_attendance_schedule.py create mode 100644 hr_timesheet_attendance_schedule/models/hr_timesheet_sheet.py create mode 100644 hr_timesheet_attendance_schedule/models/res_company.py create mode 100644 hr_timesheet_attendance_schedule/models/res_config.py create mode 100644 hr_timesheet_attendance_schedule/security/ir.model.access.csv create mode 100644 hr_timesheet_attendance_schedule/static/description/icon.png create mode 100644 hr_timesheet_attendance_schedule/views/hr_attendance_config_setting_views.xml create mode 100644 hr_timesheet_attendance_schedule/views/hr_timesheet_attendance_schedule_views.xml create mode 100644 hr_timesheet_attendance_schedule/views/hr_timesheet_sheet_views.xml diff --git a/hr_timesheet_attendance_schedule/README.rst b/hr_timesheet_attendance_schedule/README.rst new file mode 100644 index 00000000..80f02052 --- /dev/null +++ b/hr_timesheet_attendance_schedule/README.rst @@ -0,0 +1,39 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +============================= +Timesheet Attendance Schedule +============================= + + +Installation +============ + +To install this module, you need to: + +1. Clone the branch 8.0 of the repository https://github.com/open-synergy/opnsynid-hr +2. Add the path to this repository in your configuration (addons-path) +3. Update the module list +4. Go to menu *Setting -> Modules -> Local Modules* +5. Search For *Timesheet Attendance Schedule* +6. Install the module + +Credits +======= + +Contributors +------------ + +* Michael Viriyananda +* Andhitia Rama +* Nurazmi + +Maintainer +---------- + +.. image:: https://opensynergy-indonesia.com/logo.png + :alt: OpenSynergy Indonesia + :target: https://opensynergy-indonesia.com + +This module is maintained by the OpenSynergy Indonesia. diff --git a/hr_timesheet_attendance_schedule/__init__.py b/hr_timesheet_attendance_schedule/__init__.py new file mode 100644 index 00000000..814c5234 --- /dev/null +++ b/hr_timesheet_attendance_schedule/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/hr_timesheet_attendance_schedule/__openerp__.py b/hr_timesheet_attendance_schedule/__openerp__.py new file mode 100644 index 00000000..050562bc --- /dev/null +++ b/hr_timesheet_attendance_schedule/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Timesheet Attendance Schedule", + "version": "8.0.1.0.0", + "category": "Human Resource", + "website": "https://opensynergy-indonesia.com", + "author": "OpenSynergy Indonesia", + "license": "AGPL-3", + "installable": True, + "depends": [ + "hr_timesheet_sheet", + ], + "data": [ + "security/ir.model.access.csv", + "data/ir_filters_data.xml", + "data/ir_actions_server_data.xml", + "data/base_action_rule_data.xml", + "views/hr_timesheet_sheet_views.xml", + "views/hr_timesheet_attendance_schedule_views.xml", + "views/hr_attendance_config_setting_views.xml", + ], +} diff --git a/hr_timesheet_attendance_schedule/data/base_action_rule_data.xml b/hr_timesheet_attendance_schedule/data/base_action_rule_data.xml new file mode 100644 index 00000000..890ad61a --- /dev/null +++ b/hr_timesheet_attendance_schedule/data/base_action_rule_data.xml @@ -0,0 +1,17 @@ + + + + + + + + Create Attendance Schedule + + on_write + + + + + + diff --git a/hr_timesheet_attendance_schedule/data/ir_actions_server_data.xml b/hr_timesheet_attendance_schedule/data/ir_actions_server_data.xml new file mode 100644 index 00000000..12812abc --- /dev/null +++ b/hr_timesheet_attendance_schedule/data/ir_actions_server_data.xml @@ -0,0 +1,21 @@ + + + + + + + + Create Attendance Schedule + + ir.actions.server + + True + code + object.action_create_attendance_schedule() + + + + + + diff --git a/hr_timesheet_attendance_schedule/data/ir_filters_data.xml b/hr_timesheet_attendance_schedule/data/ir_filters_data.xml new file mode 100644 index 00000000..82f030be --- /dev/null +++ b/hr_timesheet_attendance_schedule/data/ir_filters_data.xml @@ -0,0 +1,16 @@ + + + + + + + + After Attendance Schedule Creation + hr_timesheet_sheet.sheet + [["state","=","draft"]] + + + + + diff --git a/hr_timesheet_attendance_schedule/models/__init__.py b/hr_timesheet_attendance_schedule/models/__init__.py new file mode 100644 index 00000000..a4216142 --- /dev/null +++ b/hr_timesheet_attendance_schedule/models/__init__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import hr_attendance +from . import hr_timesheet_attendance_schedule +from . import hr_timesheet_sheet +from . import res_company +from . import res_config diff --git a/hr_timesheet_attendance_schedule/models/hr_attendance.py b/hr_timesheet_attendance_schedule/models/hr_attendance.py new file mode 100644 index 00000000..66a88ecd --- /dev/null +++ b/hr_timesheet_attendance_schedule/models/hr_attendance.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from dateutil.relativedelta import relativedelta +from openerp import models, fields, api + + +class HrAttendance(models.Model): + _inherit = "hr.attendance" + + @api.multi + @api.depends("name") + def _compute_schedule(self): + obj_schedule = self.env["hr.timesheet_attendance_schedule"] + for attn in self: + company = attn.employee_id.company_id + early_buffer = fields.Datetime.from_string(attn.name) + \ + relativedelta(hours=company.early_attendance_buffer) + early_buffer = fields.Datetime.to_string(early_buffer) + late_buffer = fields.Datetime.from_string(attn.name) + \ + relativedelta(hours=-company.late_attendance_buffer) + late_buffer = fields.Datetime.to_string(late_buffer) + + criteria = [ + ("employee_id", "=", attn.employee_id.id), + ("date_start", "<=", early_buffer), + ("date_end", ">=", late_buffer), + ] + schedules = obj_schedule.search(criteria, limit=1) + attn.schedule_id = schedules[0].id if len(schedules) > 0 else False + + schedule_id = fields.Many2one( + string="Attendance Schedule", + comodel_name="hr.timesheet_attendance_schedule", + compute="_compute_schedule", + store=True, + ) diff --git a/hr_timesheet_attendance_schedule/models/hr_timesheet_attendance_schedule.py b/hr_timesheet_attendance_schedule/models/hr_timesheet_attendance_schedule.py new file mode 100644 index 00000000..817259f3 --- /dev/null +++ b/hr_timesheet_attendance_schedule/models/hr_timesheet_attendance_schedule.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields, api + + +class HrTimesheetAttendanceSchedule(models.Model): + _name = "hr.timesheet_attendance_schedule" + _description = "Timesheet Attendance Schedule" + _order = "sheet_id, date_start" + + @api.multi + @api.depends("attendance_ids") + def _compute_attendance(self): + for schedule in self: + attendances = schedule.attendance_ids.filtered( + lambda r: r.action == "sign_in").sorted(key=lambda r: r.name) + schedule.start_attendance_id = attendances[ + 0].id if len(attendances) > 0 else False + + attendances = schedule.attendance_ids.\ + filtered(lambda r: r.action == "sign_out").\ + sorted(key=lambda r: r.name, reverse=True) + schedule.end_attendance_id = attendances[ + 0].id if len(attendances) > 0 else False + + @api.multi + @api.depends( + "start_attendance_id", "end_attendance_id", + ) + def _compute_state(self): + for attn in self: + if attn.start_attendance_id and \ + attn.end_attendance_id: + attn.state = "present" + elif (attn.start_attendance_id and not attn.end_attendance_id) or \ + (not attn.start_attendance_id and attn.end_attendance_id): + attn.state = "open" + elif not attn.start_attendance_id and \ + not attn.end_attendance_id: + attn.state = "absence" + + @api.multi + @api.depends( + "date_start", "date_end", + "start_attendance_id", "end_attendance_id", + "start_attendance_id.name", "end_attendance_id.name", + ) + def _compute_work_hour(self): + for attn in self: + schedule_work_hour = real_work_hour = early_start_hour = \ + late_start_hour = finish_early_hour = finish_late_hour = \ + 0.0 + dt_schedule_start = fields.Datetime.from_string(attn.date_start) \ + if attn.date_start else False + dt_schedule_end = fields.Datetime.from_string(attn.date_end) \ + if attn.date_end else False + dt_real_start = fields.Datetime.\ + from_string(attn.start_attendance_id.name) if attn.\ + start_attendance_id else False + dt_real_end = fields.Datetime.\ + from_string(attn.end_attendance_id.name) if attn.\ + end_attendance_id else False + + if dt_schedule_start and dt_schedule_end: + schedule_work_hour = \ + (dt_schedule_end - dt_schedule_start).total_seconds() / \ + 3600.0 + + if dt_real_start and dt_real_end: + real_work_hour = \ + (dt_real_end - dt_real_start).total_seconds() / \ + 3600.0 + + if dt_schedule_start and dt_real_start: + if dt_schedule_start > dt_real_start: + early_start_hour = (dt_schedule_start - dt_real_start).\ + total_seconds() / 3600.0 + + if dt_schedule_start < dt_real_start: + late_start_hour = (dt_real_start - dt_schedule_start).\ + total_seconds() / 3600.0 + + if dt_schedule_end and dt_real_end: + if dt_schedule_end > dt_real_end: + finish_early_hour = (dt_schedule_end - dt_real_end).\ + total_seconds() / 3600.0 + + if dt_schedule_end < dt_real_end: + finish_late_hour = (dt_real_end - dt_schedule_end).\ + total_seconds() / 3600.0 + + attn.schedule_work_hour = schedule_work_hour + attn.real_work_hour = real_work_hour + attn.early_start_hour = early_start_hour + attn.late_start_hour = late_start_hour + attn.finish_early_hour = finish_early_hour + attn.finish_late_hour = finish_late_hour + + sheet_id = fields.Many2one( + string="Timesheet", + comodel_name="hr_timesheet_sheet.sheet", + ) + employee_id = fields.Many2one( + string="Employee", + related="sheet_id.employee_id", + store=True, + ) + date_start = fields.Datetime( + string="Date Start", + required=False, + ) + date_end = fields.Datetime( + string="Date End", + required=False, + ) + attendance_ids = fields.One2many( + string="Attendances", + comodel_name="hr.attendance", + inverse_name="schedule_id", + ) + start_attendance_id = fields.Many2one( + string="Start Attendance", + comodel_name="hr.attendance", + compute="_compute_attendance", + store=True, + ) + end_attendance_id = fields.Many2one( + string="End Attendance", + comodel_name="hr.attendance", + compute="_compute_attendance", + store=True, + ) + real_date_start = fields.Datetime( + string="Real Date Start", + related="start_attendance_id.name", + ) + real_date_end = fields.Datetime( + string="Real Date End", + related="end_attendance_id.name", + ) + + state = fields.Selection( + string="State", + selection=[ + ("absence", "Absence"), + ("open", "Open"), + ("present", "Present"), + ], + default="absence", + required=True, + compute="_compute_state", + store=True, + ) + schedule_work_hour = fields.Float( + string="Schedule Work Hour", + compute="_compute_work_hour", + store=True, + ) + real_work_hour = fields.Float( + string="Real Work Hour", + compute="_compute_work_hour", + store=True, + ) + early_start_hour = fields.Float( + string="Early Start", + compute="_compute_work_hour", + store=True, + ) + late_start_hour = fields.Float( + string="Late Start", + compute="_compute_work_hour", + store=True, + ) + finish_early_hour = fields.Float( + string="Finish Early", + compute="_compute_work_hour", + store=True, + ) + finish_late_hour = fields.Float( + string="Finish Late", + compute="_compute_work_hour", + store=True, + ) diff --git a/hr_timesheet_attendance_schedule/models/hr_timesheet_sheet.py b/hr_timesheet_attendance_schedule/models/hr_timesheet_sheet.py new file mode 100644 index 00000000..0b8edd63 --- /dev/null +++ b/hr_timesheet_attendance_schedule/models/hr_timesheet_sheet.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields, api + + +class HrTimesheetSheet(models.Model): + _inherit = "hr_timesheet_sheet.sheet" + + attendance_schedule_ids = fields.One2many( + string="Attendance Schedule", + comodel_name="hr.timesheet_attendance_schedule", + inverse_name="sheet_id", + readonly=True, + states={ + "draft": [ + ("readonly", False), + ], + }, + ) + + @api.multi + def action_create_attendance_schedule(self): + for sheet in self: + sheet._create_attendance_schedule() + + @api.multi + def _create_attendance_schedule(self): + self.ensure_one() + obj_schedule = self.env["hr.timesheet_attendance_schedule"] + dt_start = fields.Datetime.from_string(self.date_from) + dt_end = fields.Datetime.from_string(self.date_to) + duration = abs((dt_end - dt_start).days) + 1 + if self.contract_ids: + contract = self.contract_ids.sorted( + lambda r: r.date_start, reverse=True)[0] + + schedules = contract.working_hours._schedule_days( + days=duration, + day_date=dt_start) + for schedule in schedules[0]: + str_start = fields.Datetime.to_string(schedule[0]) + str_end = fields.Datetime.to_string(schedule[1]) + if self._check_existing_schedule(str_start, str_end): + data = { + "sheet_id": self.id, + "date_start": str_start, + "date_end": str_end, + } + obj_schedule.create(data) + + @api.multi + def _check_existing_schedule(self, dt_start, dt_end): + self.ensure_one() + result = True + obj_schedule = self.env["hr.timesheet_attendance_schedule"] + criteria = [ + ("sheet_id", "=", self.id), + ("date_start", "=", dt_start), + ("date_end", "=", dt_end), + ] + schedule_count = obj_schedule.search_count(criteria) + if schedule_count > 0: + result = False + return result diff --git a/hr_timesheet_attendance_schedule/models/res_company.py b/hr_timesheet_attendance_schedule/models/res_company.py new file mode 100644 index 00000000..42bc3c18 --- /dev/null +++ b/hr_timesheet_attendance_schedule/models/res_company.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields + + +class ResCompany(models.Model): + _inherit = "res.company" + + early_attendance_buffer = fields.Float( + string="Early Attendance Buffer", + default=0.0, + required=True, + ) + late_attendance_buffer = fields.Float( + string="Late Attendance Buffer", + default=0.0, + required=True, + ) diff --git a/hr_timesheet_attendance_schedule/models/res_config.py b/hr_timesheet_attendance_schedule/models/res_config.py new file mode 100644 index 00000000..d41ba5f7 --- /dev/null +++ b/hr_timesheet_attendance_schedule/models/res_config.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 OpenSynergy Indonesia +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields + + +class ResConfig(models.TransientModel): + _inherit = "hr.attendance_config_setting" + + early_attendance_buffer = fields.Float( + string="Early Attendance Buffer", + related="company_id.early_attendance_buffer", + ) + late_attendance_buffer = fields.Float( + string="Late Attendance Buffer", + related="company_id.late_attendance_buffer", + ) diff --git a/hr_timesheet_attendance_schedule/security/ir.model.access.csv b/hr_timesheet_attendance_schedule/security/ir.model.access.csv new file mode 100644 index 00000000..94d4ee53 --- /dev/null +++ b/hr_timesheet_attendance_schedule/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +hr_timesheet_attendance_schedule_employee,hr.timesheet_attendance_schedule - employee,model_hr_timesheet_attendance_schedule,base.group_user,1,1,1,1 +hr_timesheet_attendance_schedule_all,hr.timesheet_attendance_schedule - all,model_hr_timesheet_attendance_schedule,,1,0,0,0 diff --git a/hr_timesheet_attendance_schedule/static/description/icon.png b/hr_timesheet_attendance_schedule/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..270415f77e49a82c4e9ce797a25b915976043b99 GIT binary patch literal 14784 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 MDJmyYBV-WxKTq$;LI3~& literal 0 HcmV?d00001 diff --git a/hr_timesheet_attendance_schedule/views/hr_attendance_config_setting_views.xml b/hr_timesheet_attendance_schedule/views/hr_attendance_config_setting_views.xml new file mode 100644 index 00000000..68196b64 --- /dev/null +++ b/hr_timesheet_attendance_schedule/views/hr_attendance_config_setting_views.xml @@ -0,0 +1,31 @@ + + + + + + + + hr.attendance_config_setting form + hr.attendance_config_setting + + + + +

+
+
+
+ + + + + + + diff --git a/hr_timesheet_attendance_schedule/views/hr_timesheet_attendance_schedule_views.xml b/hr_timesheet_attendance_schedule/views/hr_timesheet_attendance_schedule_views.xml new file mode 100644 index 00000000..8355d548 --- /dev/null +++ b/hr_timesheet_attendance_schedule/views/hr_timesheet_attendance_schedule_views.xml @@ -0,0 +1,97 @@ + + + + + + + + hr.timesheet_attendance_schedule tree + hr.timesheet_attendance_schedule + + + + + + + + + + + + + + + + + + + hr.timesheet_attendance_schedule form + hr.timesheet_attendance_schedule + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + hr.timesheet_attendance_schedule search + hr.timesheet_attendance_schedule + + + + + + + + + + + + + Timesheet Attendance Schedule + ir.actions.act_window + hr.timesheet_attendance_schedule + form + tree,form + + + + + + +
+
diff --git a/hr_timesheet_attendance_schedule/views/hr_timesheet_sheet_views.xml b/hr_timesheet_attendance_schedule/views/hr_timesheet_sheet_views.xml new file mode 100644 index 00000000..80171cb1 --- /dev/null +++ b/hr_timesheet_attendance_schedule/views/hr_timesheet_sheet_views.xml @@ -0,0 +1,62 @@ + + + + + + + + hr_timesheet_sheet.sheet form + hr_timesheet_sheet.sheet + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ + +
+