diff --git a/.github/workflows/twahod-project.yml b/.github/workflows/twahod-project.yml
new file mode 100644
index 000000000..92fac8b42
--- /dev/null
+++ b/.github/workflows/twahod-project.yml
@@ -0,0 +1,17 @@
+name: Twahod Project - Pull Code
+
+on:
+ workflow_dispatch:
+
+jobs:
+ deploy_master_server:
+ name: Deploy to Master
+ runs-on: twahod-client-project-runner
+ if: github.event_name == 'workflow_dispatch' && (github.ref == 'refs/heads/master_odex-event' || github.ref == 'refs/heads/master_odex25_accounting' || github.ref == 'refs/heads/master_odex25_base' || github.ref == 'refs/heads/master_odex25_dms' || github.ref == 'refs/heads/master_odex25_fleet' || github.ref == 'refs/heads/master_odex25_ENSAN' || github.ref == 'refs/heads/master_odex25_hr' || github.ref == 'refs/heads/master_odex25_inventory' || github.ref == 'refs/heads/master_odex25_maintenance' || github.ref == 'refs/heads/master_odex25_mobile' || github.ref == 'refs/heads/master_odex25_pos' || github.ref == 'refs/heads/master_odex25_project' || github.ref == 'refs/heads/master_odex25_purchase' || github.ref == 'refs/heads/master_odex25_realstate' || github.ref == 'refs/heads/master_odex25_sales' || github.ref == 'refs/heads/master_odex25_survey' || github.ref == 'refs/heads/master_odex25_transactions' || github.ref == 'refs/heads/master_odex25_website' || github.ref == 'refs/heads/master_openeducat_erp-14.0.1.0' || github.ref == 'refs/heads/master_odex25_ensan')
+ steps:
+ - name: Checkout And Restart Project
+ run: |
+ echo "** [INFO] Running on branch --> ${GITHUB_REF#refs/heads/}"
+
+ sudo chmod +x ${{ secrets.TWAHOD_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh
+ sudo ${{ secrets.TWAHOD_STANDARD_FOLDER_PATH }}/scripts/pull_code.sh ${{ secrets.TWAHOD_PROJECT_USER }} ${{ secrets.TWAHOD_STANDARD_FOLDER_PATH }} ${{ secrets.TWAHOD_MASTER_SERVICE }} master ${GITHUB_REF#refs/heads/master_} ${GITHUB_REF#refs/heads/}
diff --git a/odex25_hr/attendances/data/ir_cron.xml b/odex25_hr/attendances/data/ir_cron.xml
index 593f9eb47..f659c47bf 100644
--- a/odex25_hr/attendances/data/ir_cron.xml
+++ b/odex25_hr/attendances/data/ir_cron.xml
@@ -1,12 +1,57 @@
We would like to inform you of the following attendance details:
+| Date | +Day | +Lateness | +Early Exit | +Note | +
|---|---|---|---|---|
| ${object.date.strftime('%Y-%m-%d')} | +${object.date.strftime('%A')} | +${object.lateness or 0} | +${object.early_exit or 0} | +${'Absent' if object.is_absent else 'Present'} | +
Please adhere to work timings. Thank you for your understanding.
+ ]]> + + + diff --git a/odex25_hr/attendances/models/hr_attendance_transactions.py b/odex25_hr/attendances/models/hr_attendance_transactions.py index 0aaa5a083..d360f8baa 100644 --- a/odex25_hr/attendances/models/hr_attendance_transactions.py +++ b/odex25_hr/attendances/models/hr_attendance_transactions.py @@ -12,9 +12,9 @@ class HrAttendanceTransactions(models.Model): _order = 'date DESC' date = fields.Date(string='Day') - lateness = fields.Float(compute='get_hours') - early_exit = fields.Float(compute='get_hours') - is_absent = fields.Boolean(string='Absent', compute='get_hours',store=True) + lateness = fields.Float(compute='get_hours', widget='float_time') + early_exit = fields.Float(compute='get_hours', widget='float_time') + is_absent = fields.Boolean(string='Absent', compute='get_hours', store=True) sign_in = fields.Float() sign_out = fields.Float() approve_exit_out = fields.Boolean(string='Approve Early Exit', compute='get_hours') @@ -35,8 +35,8 @@ class HrAttendanceTransactions(models.Model): attending_type = fields.Selection([('in_cal', 'within Calendar'), ('out_cal', 'out Calendar')], string='Attending Type', default="in_cal") company_id = fields.Many2one(related='employee_id.company_id') - employee_number = fields.Char(related='employee_id.emp_no', string='Employee Number',store=True) - department_id = fields.Many2one(related='employee_id.department_id',string='Department Name' ,store=True) + employee_number = fields.Char(related='employee_id.emp_no', string='Employee Number', store=True) + department_id = fields.Many2one(related='employee_id.department_id', string='Department Name', store=True) is_branch = fields.Many2one(related='department_id.branch_name', store=True, readonly=True) def get_additional_hours(self): @@ -83,9 +83,9 @@ class HrAttendanceTransactions(models.Model): working_hours = sum(day_trans.mapped('official_hours')) \ + sum(day_trans.mapped('total_mission_hours')) \ + sum(day_trans.mapped('total_permission_hours')) - - if not item.public_holiday : - if working_hours < item.calendar_id.end_sign_in and not item.calendar_id.is_flexible \ + + if not item.public_holiday: + if working_hours < item.calendar_id.end_sign_in and not item.calendar_id.is_flexible \ or item.calendar_id.is_flexible and working_hours == 0.0: day_trans.filtered(lambda t: t.public_holiday == False).update({'is_absent': True}) if working_hours == 0.0 and item.sign_in == 0.0 and item.sign_out == 0.0 and not item.calendar_id.is_flexible: @@ -97,7 +97,7 @@ class HrAttendanceTransactions(models.Model): # if item.temp_exit: # item.approve_exit_out = True #################### Fix lateness,exit_out start ####################### - if item.temp_lateness or item.temp_exit : # solve one cases and add other case #TODO + if item.temp_lateness or item.temp_exit: # solve one cases and add other case #TODO full_max_sign_in = item.calendar_id.full_max_sign_in full_min_sign_in = item.calendar_id.full_min_sign_in working_hours = item.calendar_id.working_hours @@ -110,23 +110,23 @@ class HrAttendanceTransactions(models.Model): full_max_sign_in = item.calendar_id.shift_two_max_sign_in full_min_sign_in = item.calendar_id.shift_two_min_sign_in working_hours = item.calendar_id.shift_two_working_hours - + is_late_sign_in = item.sign_in > full_max_sign_in if item.sign_in < full_min_sign_in: expected_sign_in = full_min_sign_in - if item.sign_in >= full_min_sign_in and item.sign_in <= full_max_sign_in : + if item.sign_in >= full_min_sign_in and item.sign_in <= full_max_sign_in: expected_sign_in = item.sign_in if is_late_sign_in: expected_sign_in = full_max_sign_in expected_sign_out = expected_sign_in + working_hours is_early_sign_out = item.sign_out > 0.0 and item.sign_out < expected_sign_out - item.temp_lateness = item.sign_out > 0.0 and is_late_sign_in and item.sign_in - expected_sign_in or 0 + item.temp_lateness = item.sign_out > 0.0 and is_late_sign_in and item.sign_in - expected_sign_in or 0 item.temp_exit = is_early_sign_out and expected_sign_out - item.sign_out or 0 item.approve_lateness = is_late_sign_in item.approve_exit_out = is_early_sign_out - #if item.sign_out == 0.0: - #item.is_absent = True + # if item.sign_out == 0.0: + # item.is_absent = True #################### Fix end ####################### if item.break_duration and item.calendar_id.break_duration: # item.write({'break_duration': item.break_duration - item.calendar_id.break_duration}) #TODO @@ -338,7 +338,6 @@ class HrAttendanceTransactions(models.Model): sign_in = 0.0 sign_out = 0.0 - # sign_in, sign_out = attending_periods[0]['in'], attending_periods[-1]['out'] shift_dict['sign_in'] = sign_in and self.get_sign_time(fields.Datetime.to_string(sign_in))[0] or 0.0 @@ -627,7 +626,7 @@ class HrAttendanceTransactions(models.Model): if state is not None: return feedback @api.model - def process_attendance_scheduler_queue(self, attendance_date=None, attendance_employee=None,send_email=False): + def process_attendance_scheduler_queue(self, attendance_date=None, attendance_employee=None, send_email=False): at_device = self.env['ir.module.module'].sudo().search([('state', '=', 'installed'), ('name', '=', 'to_attendance_device_custom')]) \ and True or False @@ -821,7 +820,7 @@ class HrAttendanceTransactions(models.Model): one_in_dom = domain.copy() + [('action', '=', 'sign_in'), ('name', '<', one_max_out_st)] two_in_dom = domain.copy() + [('action', '=', 'sign_in'), ('name', '>=', one_max_out_st)] out_dom = domain.copy() + [('action', '=', 'sign_out')] - + signs_out = attendance_pool.search(out_dom, order="name asc") one_signs_in = attendance_pool.search(one_in_dom, order="name asc") two_signs_in = attendance_pool.search(two_in_dom, order="name asc") @@ -961,7 +960,8 @@ class HrAttendanceTransactions(models.Model): off_list.append(day.name.lower()) if day.name.lower() == day_item.strftime('%A').lower(): for trans in day_trans: - if emp_calendar.noke and create <= datetime.strptime(str(trans.date), "%Y-%m-%d").date(): + if emp_calendar.noke and create <= datetime.strptime(str(trans.date), + "%Y-%m-%d").date(): trans.update({'public_holiday': True}) else: if not emp_calendar.is_full_day: @@ -969,16 +969,17 @@ class HrAttendanceTransactions(models.Model): trans.update({'public_holiday': True}) elif day.shift == 'tow' and trans.sequence == 2: trans.update({'public_holiday': True}) - elif day.shift == 'both' : + elif day.shift == 'both': trans.update({'public_holiday': True}) else: trans.update({'public_holiday': True}) - + else: for trans in day_trans: if trans.public_holiday and not trans.public_holiday_id: trans_wkd = datetime.strptime(str(trans.date), "%Y-%m-%d") - if trans_wkd.strftime('%A').lower() not in off_list and not trans.public_holiday_id: + if trans_wkd.strftime( + '%A').lower() not in off_list and not trans.public_holiday_id: if emp_calendar.noke: pass else: @@ -1114,6 +1115,23 @@ class HrAttendanceTransactions(models.Model): else: return False + @api.model + def send_lateness_notifications(self): + yesterday = datetime.now().date() - timedelta(days=1) + + records_to_notify = self.search([ + ('date', '=', yesterday), '|', '|', + ('lateness', '>', 0), + ('early_exit', '>', 0), + ('is_absent', '=', True) + ]) + + template_id = self.env.ref('attendances.attendance_notification_email_template').id + for record in records_to_notify: + if template_id: + template = self.env['mail.template'].browse(template_id) + template.send_mail(record.id, force_send=True) + # @api.multi # def unlink(self): # raise UserError(_('Sorry, you can not delete an attendance transaction manually.')) diff --git a/odex25_hr/exp_hr_payroll/models/hr_salary_rule.py b/odex25_hr/exp_hr_payroll/models/hr_salary_rule.py index e1515f942..5dc3efb17 100644 --- a/odex25_hr/exp_hr_payroll/models/hr_salary_rule.py +++ b/odex25_hr/exp_hr_payroll/models/hr_salary_rule.py @@ -73,6 +73,11 @@ class HrSalaryRuleCategory(models.Model): name = fields.Char(required=True, translate=True) code = fields.Char(required=True) + rule_type = fields.Selection( + [('allowance', 'Allowance'), + ('deduction', 'Deduction')], + string='Rule Type' + ) parent_id = fields.Many2one('hr.salary.rule.category', string='Parent', help="Linking a salary category to its parent is used only for the reporting purpose.") children_ids = fields.One2many('hr.salary.rule.category', 'parent_id', string='Children')