Merge branch 'dev_odex25_hr' of https://github.com/expsa/odex25-standard-modules into bakry_hr
This commit is contained in:
commit
4cf88628c4
|
|
@ -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/}
|
||||
|
|
@ -1,12 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="hr_attendance_transaction_create" model="ir.cron">
|
||||
<field name="name">Attendance Transaction</field>
|
||||
<field name="model_id" ref="model_hr_attendance_transaction"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.process_attendance_scheduler_queue()</field>
|
||||
<field name="interval_number">12</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
<data noupdate="1">
|
||||
<record id="hr_attendance_transaction_create" model="ir.cron">
|
||||
<field name="name">Attendance Transaction</field>
|
||||
<field name="model_id" ref="model_hr_attendance_transaction"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.process_attendance_scheduler_queue()</field>
|
||||
<field name="interval_number">12</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_cron_send_lateness_notifications" model="ir.cron">
|
||||
<field name="name">Send Lateness Notifications</field>
|
||||
<field name="model_id" ref="model_hr_attendance_transaction"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.send_lateness_notifications()</field>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
<record id="attendance_notification_email_template" model="mail.template">
|
||||
<field name="name">Attendance Notification Email Template</field>
|
||||
<field name="subject">Attendance Report</field>
|
||||
<field name="email_from">${object.employee_id.work_email}</field>
|
||||
<field name="model_id" ref="attendances.model_hr_attendance_transaction"/>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="auto_delete" eval="False"/>
|
||||
<field name="body_html">
|
||||
<![CDATA[
|
||||
<p>Dear ${object.employee_id.name},</p>
|
||||
<p>We would like to inform you of the following attendance details:</p>
|
||||
<table border="1" style="width:100%; border-collapse: collapse;">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Day</th>
|
||||
<th>Lateness</th>
|
||||
<th>Early Exit</th>
|
||||
<th>Note</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${object.date.strftime('%Y-%m-%d')}</td>
|
||||
<td>${object.date.strftime('%A')}</td>
|
||||
<td>${object.lateness or 0}</td>
|
||||
<td>${object.early_exit or 0}</td>
|
||||
<td>${'Absent' if object.is_absent else 'Present'}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Please adhere to work timings. Thank you for your understanding.</p>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -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.'))
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
Loading…
Reference in New Issue