Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ignore known erpnext exceptions #30

Merged
merged 2 commits into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions erpnext_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@
import pickledb
from zk import ZK, const

EMPLOYEE_NOT_FOUND_ERROR_MESSAGE = "No Employee found for the given employee field value."
EMPLOYEE_NOT_FOUND_ERROR_MESSAGE = "No Employee found for the given employee field value"
EMPLOYEE_INACTIVE_ERROR_MESSAGE = "Transactions cannot be created for an Inactive Employee"
DUPLICATE_EMPLOYEE_CHECKIN_ERROR_MESSAGE = "This employee already has a log with the same timestamp"
allowlisted_errors = [EMPLOYEE_NOT_FOUND_ERROR_MESSAGE, EMPLOYEE_INACTIVE_ERROR_MESSAGE, DUPLICATE_EMPLOYEE_CHECKIN_ERROR_MESSAGE]

if hasattr(config,'allowed_exceptions'):
allowlisted_errors_temp = []
for error_number in config.allowed_exceptions:
allowlisted_errors_temp.append(allowlisted_errors[error_number-1])
allowlisted_errors = allowlisted_errors_temp

device_punch_values_IN = getattr(config, 'device_punch_values_IN', [0,4])
device_punch_values_OUT = getattr(config, 'device_punch_values_OUT', [1,5])

Expand Down Expand Up @@ -40,7 +50,7 @@ def main():
for device in config.devices:
device_attendance_logs = None
info_logger.info("Processing Device: "+ device['device_id'])
dump_file = config.LOGS_DIRECTORY+'/'+device['ip'].replace('.', '_')+'_last_fetch_dump.json'
dump_file = get_dump_file_name_and_directory(device['device_id'], device['ip'])
if os.path.exists(dump_file):
info_logger.error('Device Attendance Dump Found in Log Directory. This can mean the program crashed unexpectedly. Retrying with dumped data.')
with open(dump_file, 'r') as f:
Expand Down Expand Up @@ -125,7 +135,7 @@ def pull_process_and_push_data(device, device_attendance_logs=None):
str(device_attendance_log['user_id']), str(device_attendance_log['timestamp'].timestamp()),
str(device_attendance_log['punch']), str(device_attendance_log['status']),
json.dumps(device_attendance_log, default=str)]))
if EMPLOYEE_NOT_FOUND_ERROR_MESSAGE not in erpnext_message:
if not(any(error in erpnext_message for error in allowlisted_errors)):
raise Exception('API Call to ERPNext Failed.')


Expand All @@ -146,7 +156,7 @@ def get_all_attendance_from_device(ip, port=4370, timeout=30, device_id=None, cl
if len(attendances):
# keeping a backup before clearing data incase the programs fails.
# if everything goes well then this file is removed automatically at the end.
dump_file_name = config.LOGS_DIRECTORY+'/' + device_id + "_" + ip.replace('.', '_') + '_last_fetch_dump.json'
dump_file_name = get_dump_file_name_and_directory(device_id, ip)
with open(dump_file_name, 'w+') as f:
f.write(json.dumps(list(map(lambda x: x.__dict__, attendances)), default=datetime.datetime.timestamp))
if clear_from_device_on_fetch:
Expand Down Expand Up @@ -276,6 +286,9 @@ def setup_logger(name, log_file, level=logging.INFO, formatter=None):

return logger

def get_dump_file_name_and_directory(device_id, device_ip):
return config.LOGS_DIRECTORY + '/' + device_id + "_" + device_ip.replace('.', '_') + '_last_fetch_dump.json'

def _apply_function_to_key(obj, key, fn):
obj[key] = fn(obj[key])
return obj
Expand Down
12 changes: 11 additions & 1 deletion local_config.py.template
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,17 @@ devices = [
{'device_id':'test_2','ip':'192.168.2.209', 'punch_direction': None, 'clear_from_device_on_fetch': False}
]

# Configs updating sync timestamp in the Shift Type DocType
# Configs updating sync timestamp in the Shift Type DocType
# please, read this thread to know why this is necessary https://discuss.erpnext.com/t/v-12-hr-auto-attendance-purpose-of-last-sync-of-checkin-in-shift-type/52997
shift_type_device_mapping = [
{'shift_type_name': ['Shift1'], 'related_device_id': ['test_1','test_2']}
]


# Ignore following exceptions thrown by ERPNext and continue importing punch logs.
# Note: All other exceptions will halt the punch log import to erpnext.
# 1. No Employee found for the given employee User ID in the Biometric device.
# 2. Employee is inactive for the given employee User ID in the Biometric device.
# 3. Duplicate Employee Checkin found. (This exception can happen if you have cleared the logs/status.json of this script)
# Use the corresponding number to ignore the above exceptions. (Default: Ignores all the listed exceptions)
allowed_exceptions = [1,2,3]