odex25_standard/odex25_mobile/odex_mobile/controllers/attendance.py

388 lines
22 KiB
Python

# -*- coding: utf-8 -*-
import werkzeug
import calendar
from odoo import http, tools
from odoo.http import request, Response
from odoo.addons.auth_signup.models.res_users import SignupError
from odoo.exceptions import UserError
from datetime import datetime
import base64
from ..validator import validator
from ..http_helper import http_helper
import json
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
import logging
_logger = logging.getLogger(__name__)
from odoo.tools.translate import _
import re
from odoo import fields
SENSITIVE_FIELDS = ['password', 'password_crypt', 'new_password', 'create_uid', 'write_uid']
class AttendanceController(http.Controller):
# Zoons
@http.route(['/rest_api/v1/zoons'], type='http', auth='none', csrf=False, methods=['GET'])
def get_zone(self, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
employee = http.request.env['hr.employee'].search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
try:
zone = http.request.env['attendance.zone'].search([('employee_ids', 'in', employee.id)])
li = []
general_zoons = False
if zone:
general = zone.filtered(lambda r:r.general)
specific = zone.filtered(lambda r:r.specific)
general_zoons = True if general else False
for z in specific:
value = {'id': z.id, 'name': z.zone, 'latitude': z.latitude, 'longitude': z.longitude, 'allowed_range': z.allowed_range,
'loc_ch_intv': z.loc_ch_intv, 'loc_ch_dist': z.loc_ch_dist, 'srv_ch_tmout': z.srv_ch_tmout}
li.append(value)
return http_helper.response(message="Data Found", data={'general_zoons':general_zoons, 'specific_zoons':li})
except Exception as e:
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
# First check in Last check out
@http.route(['/rest_api/v1/checks'], type='http', auth='none', csrf=False, methods=['GET'])
def get_check_in_out(self, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
if not body.get('date'):
return http_helper.response(code=400, message=_("Enter Data First"), success=False)
employee = http.request.env['hr.employee'].sudo().search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_("You Have issue in your employee profile. please check with one of your team admins"), success=False)
date = datetime.strptime(body.get('date'), DEFAULT_SERVER_DATE_FORMAT)
try:
attendance = http.request.env['attendance.attendance'].search([('employee_id', '=', employee.id), ('action_date', '=', date)])
li = []
in_rec = False
out_rec = False
checks_in = attendance.filtered(lambda r:r.action == 'sign_in').mapped('name')
check_in = min(checks_in) if checks_in else False
if check_in:
in_rec = attendance.filtered(lambda r:r.name == check_in and r.action == 'sign_in')
if in_rec:
data = self.get_check_records(in_rec[0])
li.append(data)
check_outs = attendance.filtered(lambda r:r.action == 'sign_out').mapped('name')
check_out = max(check_outs) if check_outs else False
if check_out:
out_rec = attendance.filtered(lambda r:r.name == check_out and r.action == 'sign_out')
if out_rec:
data = self.get_check_records(out_rec[0])
li.append(data)
return http_helper.response(message="Data Found", data={'checks': li})
except Exception as e:
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
def get_check_records(self, action):
date = action.name.time()
data = {
"id": action.id,
"action": action.action,
"time": str(date),
"location": {
"latitude": action.latitude,
"longitude": action.longitude,
}}
return data
@http.route(['/rest_api/v1/refresh'], type='http', auth='none', csrf=False, methods=['GET'])
def refresh_attendance(self, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_(
"You are not allowed to perform this operation. please check with one of your team admins"),
success=False)
employee = http.request.env['hr.employee'].search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_(
"You are not allowed to perform this operation. please check with one of your team admins"),
success=False)
try:
data = {}
records = employee.resource_calendar_id
shifts = {}
if records:
data.update({
'shift_start_time': '{0:02.0f}:{1:02.0f}'.format(*divmod(records.full_min_sign_in * 60, 60))if records.is_full_day else
['{0:02.0f}:{1:02.0f}'.format(*divmod(records.shift_one_min_sign_in * 60, 60)),
'{0:02.0f}:{1:02.0f}'.format(*divmod(records.shift_two_min_sign_in * 60, 60)), ],
'shift_end_time': '{0:02.0f}:{1:02.0f}'.format(*divmod(records.full_min_sign_out * 60, 60)) if records.is_full_day else
['{0:02.0f}:{1:02.0f}'.format(*divmod(records.shift_one_min_sign_out * 60, 60)),
'{0:02.0f}:{1:02.0f}'.format(*divmod(records.shift_two_min_sign_out * 60, 60)), ],
})
attendance = http.request.env['attendance.attendance'].sudo().search([('employee_id', '=', employee.id), ], order='name desc',
limit=1)
if attendance:
date = attendance.name.time()
data.update({'id': attendance.id , 'action': attendance.action,
'attendance_status': attendance.action, 'time': str(date), 'zone': attendance.zone,
'longitude': attendance.longitude, 'latitude': attendance.latitude})
_logger.error(data)
return http_helper.response(message="Refresh Successfully", data=data)
else:
data.update({'attendance_status':'sign_out'})
return http_helper.response(message="Refresh Successfully", data=data)
except Exception as e:
http.request._cr.rollback()
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
# Check In Out
@http.route(['/rest_api/v1/checks'], type='http', auth='none', csrf=False, methods=['POST'])
def create_check_in_out(self, system_checkout=None, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
if not body.get('action'):
return http_helper.response(code=400, message=_("Enter Check in type"), success=False)
if not body.get('device_id'):
return http_helper.response(code=400, message=_("Enter Device Id"), success=False)
if not body.get('latitude') or not body.get('longitude'):
return http_helper.response(code=400, message=_("Enter Zone Data for Check in"), success=False)
employee = http.request.env['hr.employee'].search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
if employee.device_id != body.get('device_id'):
return http_helper.errcode(code=403, message=_("Device id not matching with already exist in system please contact system admin"))
try:
zones = http.request.env['attendance.zone'].search([('employee_ids', 'in', employee.id)])
if not zones:
return http_helper.errcode(code=403, message=_("Employee not in any Zone,Contact Admin "))
zone = http.request.env['attendance.zone'].search([('id', '=', body.get('id'))]) if body.get(
'id') else False
rec = http.request.env['attendance.attendance'].sudo().search([('employee_id', '=', employee.id), ],
order='name desc',
limit=1)
system_checkout = json.loads(body.get('system_checkout')) if 'system_checkout' in body else False
if not rec or rec and rec.action != body.get('action'):
attendance = http.request.env['attendance.attendance'].create({
'employee_id':employee.id,
'action':body.get('action'),
'action_type':"system_checkout" if body.get('action') == 'sign_out' and system_checkout == True else 'application',
'name': fields.datetime.now(),
# 'device_id':body.get('device_id'),
'zone': (zone.zone or zone.name) if zone else "%s,%s" % (body.get('longitude'), body.get('latitude')),
'zone_name': zone.id if zone else False,
'longitude': body.get('longitude'),
'latitude':body.get('latitude'),
})
if attendance:
if body.get('action') == 'sign_out' and system_checkout == True:
msg = (_("System Force Sign out Due to Change Location Permission "))
subject = (_("System Force Sign out"))
self.send_msg(employee, msg, subject)
date = attendance.name.time()
data = {
"id": attendance.id,
"action": attendance.action,
"attendance_status": attendance.action,
"time": str(date),
"zone": (attendance.zone_name.zone or attendance.zone_name.name) if attendance.zone_name else attendance.zone,
"longitude": attendance.longitude,
"latitude": attendance.latitude,
"range": zone.allowed_range if zone else False,
}
msg = (_("Check Out successfully")) if body.get('action') == 'sign_out' else (_("Check in successfully"))
else:
msg = (_("Check Fail Due To Duplication"))
data = {}
return http_helper.response(msg, data={'checks': [data]})
except Exception as e:
http.request._cr.rollback()
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
# Get Attendance Transaction Records
@http.route(['/rest_api/v1/attendaces'], type='http', auth='none', csrf=False, methods=['GET'])
def get_attendance_transactions(self, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
if not body.get('date'):
return http_helper.response(code=400, message=_("Enter Date First"), success=False)
employee = http.request.env['hr.employee'].search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
date = datetime.strptime(body.get('date'), DEFAULT_SERVER_DATE_FORMAT).date()
year = date.year
month = date.month
month_start = datetime(year, month, 1).date()
last = calendar.monthrange(year, month)[1]
month_end = datetime(year, month, last).date()
try:
records = http.request.env['hr.attendance.transaction'].search([('employee_id', '=', employee.id),
('normal_leave', '=', False), ('public_holiday', '=', False), ('is_absent', '=', False), ('date', '>=', month_start), ('date', '<=', month_end)])
li = []
if records:
for rec in records:
attendance = {
'id':rec.id,
'date':str(rec.date),
'first_check_in':rec.sign_in,
'last_check_out':rec.sign_out,
'total_time':rec.office_hours,
}
li.append(attendance)
return http_helper.response(message="Data Found", data={'attendaces': li})
except Exception as e:
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
# Get shift
@http.route(['/rest_api/v1/shifts'], type='http', auth='none', csrf=False, methods=['GET'])
def get_shift(self, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
employee = http.request.env['hr.employee'].sudo().search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_("You are not allowed to perform this operation. please check with one of your team admins"), success=False)
try:
records = employee.resource_calendar_id
shifts = []
if records:
shifts.append({
'start_time':records.full_min_sign_in if records.is_full_day else records.shift_one_min_sign_in,
'end_time':records.full_min_sign_out if records.is_full_day else records.shift_one_min_sign_out,
})
return http_helper.response(message=_("Data Found successfully"), data={'shifts': shifts})
except Exception as e:
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
@http.route(['/rest_api/v1/auto_checkout'], type='http', auth='none', csrf=False, methods=['POST'])
def auto_checkout(self, in_zone=False, **kw):
http_method, body, headers, token = http_helper.parse_request()
result = validator.verify_token(token)
if not result['status']:
return http_helper.errcode(code=result['code'], message=result['message'])
user = validator.verify(token)
if not user:
return http_helper.response(code=400, message=_(
"You are not allowed to perform this operation. please check with one of your team admins"),
success=False)
employee = http.request.env['hr.employee'].search([('user_id', '=', user.id)], limit=1)
if not employee:
return http_helper.response(code=400, message=_(
"You are not allowed to perform this operation. please check with one of your team admins"),
success=False)
try:
if json.loads(body['in_zone']):
records = employee.attendance_log_ids.sudo().filtered(lambda r: str(r.date) == str(datetime.today().date()) and r.old == False)
for r in records:
r.old = True
return http_helper.response(message="Old Record Done", data={'status': True})
else:
attendance = http.request.env['attendance.attendance'].sudo().search(
[('employee_id', '=', employee.id), ], order='name desc',
limit=1)
if attendance.action == 'sign_in':
records = employee.attendance_log_ids.sudo().filtered(lambda r: r.old == False and str(r.date) == str(datetime.today().date()))
# records = employee.attendance_log_ids.sudo().filtered(lambda r: r.old == False and r.date == str(datetime.today().date()))
if records:
n = len(records)
last = records[n - 1]
last = fields.Datetime.from_string(last.time)
now = datetime.now()
if now > last:
diff = now - last
diff = diff.seconds / 60
auto = request.env.user.company_id.auto_checkout if request.env.user.company_id.auto_checkout > 0 else 5
if diff >= auto:
attendance = http.request.env['attendance.attendance'].create({
'employee_id': employee.id,
'action':'sign_out',
'action_type': 'auto',
'name': fields.datetime.now(),
# 'device_id': body.get('device_id'),
'zone': "%s,%s" % (body.get('longitude'), body.get('latitude')),
'longitude': body.get('longitude'),
'latitude': body.get('latitude'),
})
msg = (_("Auto Checkout successfully"))
subject = (_("Auto Checkout"))
self.send_msg(employee, msg, subject)
records = employee.attendance_log_ids.sudo().filtered(
lambda r: str(r.date) == str(datetime.today().date()) and r.old == False)
for r in records:
r.old = True
return http_helper.response(message="Auto Checkout successfully", data={'status': True})
else:
msg = (_("You are out of attendance zone you will be auto sin out "))
subject = (_("Auto Sign out"))
self.send_msg(employee, msg, subject)
return http_helper.response(message="Auto Checkout Fail and Send", data={'status': False})
else:
self.create_log(employee, body.get('longitude'), body.get('latitude'))
msg = (_("You are out of attendance zone you will be auto sin out "))
subject = (_("Auto Sign out"))
self.send_msg(employee, msg, subject)
return http_helper.response(message="Auto Checkout Fail and Send", data={'status': False})
else:
return http_helper.response(message="You are not Checked in yet", data={'status': True})
except Exception as e:
http.request._cr.rollback()
_logger.error(str(e))
message = validator.get_server_error(e, user)
return http_helper.errcode(code=403, message=message)
def send_msg(self, emp, msg, subject):
if emp.user_id.partner_id:
partner_id = emp.user_id.partner_id
partner_id.send_notification(
subject, msg, data=None, all_device=True)
emp.send_push_notification(title=subject, body=msg)
def create_log(self, employee, longitude, latitude):
attendance = http.request.env['attendance.log'].create({
'employee_id': employee.id,
'time': fields.datetime.now(),
'date': datetime.today().date(),
'longitude': longitude,
'latitude':latitude,
})