horilla-opensource / horilla

Horilla is a free and open source HR software.
https://www.horilla.com/
GNU Lesser General Public License v2.1
138 stars 92 forks source link

In Windows, Migration of tables fails with MySQL database #199

Open rbale0831 opened 2 months ago

rbale0831 commented 2 months ago

Bug Report

Description

I'm trying to install the application using the MySQL database. The application is throwing warning's and error's while using migrations and also while creating a horilla user. I'm not able to start the application using MySQL database

Actual Behavior

C:\Horilla>git clone https://github.com/horilla-opensource/horilla.git
Cloning into 'horilla'...
remote: Enumerating objects: 35440, done.
remote: Counting objects: 100% (3289/3289), done.
remote: Compressing objects: 100% (1379/1379), done.
remote: Total 35440 (delta 1852), reused 3091 (delta 1808), pack-reused 32151
Receiving objects: 100% (35440/35440), 66.97 MiB | 1.20 MiB/s, done.
Resolving deltas: 100% (19257/19257), done.
Updating files: 100% (2127/2127), done.

C:\Horilla>cd horilla

C:\Horilla\horilla>git checkout development
branch 'development' set up to track 'origin/development'.
Switched to a new branch 'development'

C:\Horilla\horilla>git branch
* development
  master

C:\Horilla\horilla>code .

C:\Horilla\horilla>python manage.py makemigrations
Migrations for 'horilla_audit':
  horilla_audit\migrations\0001_initial.py
    - Create model AuditTag
    - Create model HistoryTrackingFields
    - Create model AccountBlockUnblock
Migrations for 'asset':
  asset\migrations\0001_initial.py
    - Create model Asset
    - Create model AssetAssignment
    - Create model AssetCategory
    - Create model AssetDocuments
    - Create model AssetLot
    - Create model AssetReport
    - Create model ReturnImages
    - Create model AssetRequest
  asset\migrations\0002_initial.py
    - Add field requested_employee_id to assetrequest
    - Add field asset_id to assetreport
    - Add field created_by to assetreport
    - Add field modified_by to assetreport
    - Add field company_id to assetlot
    - Add field created_by to assetlot
    - Add field modified_by to assetlot
    - Add field asset_report to assetdocuments
    - Add field created_by to assetdocuments
    - Add field modified_by to assetdocuments
    - Add field company_id to assetcategory
    - Add field created_by to assetcategory
    - Add field modified_by to assetcategory
    - Add field asset_id to assetassignment
    - Add field assign_images to assetassignment
    - Add field assigned_by_employee_id to assetassignment
    - Add field assigned_to_employee_id to assetassignment
    - Add field created_by to assetassignment
    - Add field modified_by to assetassignment
    - Add field return_images to assetassignment
    - Add field asset_category_id to asset
    - Add field asset_lot_number_id to asset
    - Add field created_by to asset
    - Add field modified_by to asset
    - Add field owner to asset
Migrations for 'attendance':
  attendance\migrations\0001_initial.py
    - Create model Attendance
    - Create model AttendanceActivity
    - Create model AttendanceGeneralSetting
    - Create model AttendanceLateComeEarlyOut
    - Create model AttendanceOverTime
    - Create model AttendanceRequestComment
    - Create model AttendanceRequestFile
    - Create model AttendanceValidationCondition
    - Create model GraceTime
    - Create model HistoricalAttendance
    - Create model PenaltyAccount
  attendance\migrations\0002_initial.py
    - Add field employee_id to penaltyaccount
    - Add field late_early_id to penaltyaccount
    - Add field leave_request_id to penaltyaccount
    - Add field leave_type_id to penaltyaccount
    - Add field modified_by to penaltyaccount
    - Add field attendance_day to historicalattendance
    - Add field created_by to historicalattendance
    - Add field employee_id to historicalattendance
    - Add field history_relation to historicalattendance
    - Add field history_tags to historicalattendance
    - Add field history_user to historicalattendance
    - Add field modified_by to historicalattendance
    - Add field shift_id to historicalattendance
    - Add field work_type_id to historicalattendance
    - Add field company_id to gracetime
    - Add field created_by to gracetime
    - Add field modified_by to gracetime
    - Add field company_id to attendancevalidationcondition
    - Add field created_by to attendancevalidationcondition
    - Add field modified_by to attendancevalidationcondition
    - Add field created_by to attendancerequestfile
    - Add field modified_by to attendancerequestfile
    - Add field created_by to attendancerequestcomment
    - Add field employee_id to attendancerequestcomment
    - Add field files to attendancerequestcomment
    - Add field modified_by to attendancerequestcomment
    - Add field request_id to attendancerequestcomment
    - Add field created_by to attendanceovertime
    - Add field employee_id to attendanceovertime
    - Add field modified_by to attendanceovertime
    - Add field attendance_id to attendancelatecomeearlyout
    - Add field created_by to attendancelatecomeearlyout
    - Add field employee_id to attendancelatecomeearlyout
    - Add field modified_by to attendancelatecomeearlyout
    - Add field company_id to attendancegeneralsetting
    - Add field created_by to attendancegeneralsetting
    - Add field modified_by to attendancegeneralsetting
    - Add field created_by to attendanceactivity
    - Add field employee_id to attendanceactivity
    - Add field modified_by to attendanceactivity
    - Add field shift_day to attendanceactivity
    - Add field attendance_day to attendance
    - Add field created_by to attendance
    - Add field employee_id to attendance
    - Add field modified_by to attendance
    - Add field shift_id to attendance
    - Add field work_type_id to attendance
    - Alter unique_together for attendanceovertime (1 constraint(s))
    - Alter unique_together for attendancelatecomeearlyout (1 constraint(s))
    - Alter unique_together for attendance (1 constraint(s))
Migrations for 'base':
  base\migrations\0001_initial.py
    - Create model Announcement
    - Create model AnnouncementComment
    - Create model AnnouncementExpire
    - Create model AnnouncementView
    - Create model Attachment
    - Create model BaserequestFile
    - Create model BiometricAttendance
    - Create model Company
    - Create model DashboardEmployeeCharts
    - Create model Department
    - Create model DriverViewed
    - Create model DynamicEmailConfiguration
    - Create model DynamicPagination
    - Create model EmailLog
    - Create model EmployeeShift
    - Create model EmployeeShiftDay
    - Create model EmployeeShiftSchedule
    - Create model EmployeeType
    - Create model HistoricalRotatingShiftAssign
    - Create model HistoricalRotatingWorkTypeAssign
    - Create model HistoricalShiftRequest
    - Create model HistoricalWorkTypeRequest
    - Create model JobPosition
    - Create model JobRole
    - Create model MultipleApprovalCondition
    - Create model MultipleApprovalManagers
    - Create model RotatingShift
    - Create model RotatingShiftAssign
    - Create model RotatingWorkType
    - Create model RotatingWorkTypeAssign
    - Create model ShiftRequest
    - Create model ShiftRequestComment
    - Create model Tags
    - Create model WorkType
    - Create model WorkTypeRequest
    - Create model WorkTypeRequestComment
  base\migrations\0002_initial.py
    - Add field employee_id to worktyperequestcomment
    - Add field files to worktyperequestcomment
    - Add field modified_by to worktyperequestcomment
    - Add field request_id to worktyperequestcomment
    - Add field created_by to worktyperequest
    - Add field employee_id to worktyperequest
    - Add field modified_by to worktyperequest
    - Add field previous_work_type_id to worktyperequest
    - Add field work_type_id to worktyperequest
    - Add field company_id to worktype
    - Add field created_by to worktype
    - Add field modified_by to worktype
    - Add field company_id to tags
    - Add field created_by to tags
    - Add field modified_by to tags
    - Add field created_by to shiftrequestcomment
    - Add field employee_id to shiftrequestcomment
    - Add field files to shiftrequestcomment
    - Add field modified_by to shiftrequestcomment
    - Add field request_id to shiftrequestcomment
    - Add field created_by to shiftrequest
    - Add field employee_id to shiftrequest
    - Add field modified_by to shiftrequest
    - Add field previous_shift_id to shiftrequest
    - Add field reallocate_to to shiftrequest
    - Add field shift_id to shiftrequest
    - Add field created_by to rotatingworktypeassign
    - Add field current_work_type to rotatingworktypeassign
    - Add field employee_id to rotatingworktypeassign
    - Add field modified_by to rotatingworktypeassign
    - Add field next_work_type to rotatingworktypeassign
    - Add field rotating_work_type_id to rotatingworktypeassign
    - Add field created_by to rotatingworktype
    - Add field employee_id to rotatingworktype
    - Add field modified_by to rotatingworktype
    - Add field work_type1 to rotatingworktype
    - Add field work_type2 to rotatingworktype
    - Add field created_by to rotatingshiftassign
    - Add field current_shift to rotatingshiftassign
    - Add field employee_id to rotatingshiftassign
    - Add field modified_by to rotatingshiftassign
    - Add field next_shift to rotatingshiftassign
    - Add field rotating_shift_id to rotatingshiftassign
    - Add field created_by to rotatingshift
    - Add field employee_id to rotatingshift
    - Add field modified_by to rotatingshift
    - Add field shift1 to rotatingshift
    - Add field shift2 to rotatingshift
    - Add field condition_id to multipleapprovalmanagers
    - Add field created_by to multipleapprovalcondition
    - Add field department to multipleapprovalcondition
    - Add field modified_by to multipleapprovalcondition
    - Add field company_id to jobrole
    - Add field created_by to jobrole
    - Add field job_position_id to jobrole
    - Add field modified_by to jobrole
    - Add field company_id to jobposition
    - Add field created_by to jobposition
    - Add field department_id to jobposition
    - Add field modified_by to jobposition
    - Add field created_by to historicalworktyperequest
    - Add field employee_id to historicalworktyperequest
    - Add field history_relation to historicalworktyperequest
    - Add field history_tags to historicalworktyperequest
    - Add field history_user to historicalworktyperequest
    - Add field modified_by to historicalworktyperequest
    - Add field previous_work_type_id to historicalworktyperequest
    - Add field work_type_id to historicalworktyperequest
    - Add field created_by to historicalshiftrequest
    - Add field employee_id to historicalshiftrequest
    - Add field history_relation to historicalshiftrequest
    - Add field history_tags to historicalshiftrequest
    - Add field history_user to historicalshiftrequest
    - Add field modified_by to historicalshiftrequest
    - Add field previous_shift_id to historicalshiftrequest
    - Add field reallocate_to to historicalshiftrequest
    - Add field shift_id to historicalshiftrequest
    - Add field created_by to historicalrotatingworktypeassign
    - Add field current_work_type to historicalrotatingworktypeassign
    - Add field employee_id to historicalrotatingworktypeassign
    - Add field history_relation to historicalrotatingworktypeassign
    - Add field history_tags to historicalrotatingworktypeassign
    - Add field history_user to historicalrotatingworktypeassign
    - Add field modified_by to historicalrotatingworktypeassign
    - Add field next_work_type to historicalrotatingworktypeassign
    - Add field rotating_work_type_id to historicalrotatingworktypeassign
    - Add field created_by to historicalrotatingshiftassign
    - Add field current_shift to historicalrotatingshiftassign
    - Add field employee_id to historicalrotatingshiftassign
    - Add field history_relation to historicalrotatingshiftassign
    - Add field history_tags to historicalrotatingshiftassign
    - Add field history_user to historicalrotatingshiftassign
    - Add field modified_by to historicalrotatingshiftassign
    - Add field next_shift to historicalrotatingshiftassign
    - Add field rotating_shift_id to historicalrotatingshiftassign
    - Add field company_id to employeetype
    - Add field created_by to employeetype
    - Add field modified_by to employeetype
    - Add field company_id to employeeshiftschedule
    - Add field created_by to employeeshiftschedule
    - Add field day to employeeshiftschedule
    - Add field modified_by to employeeshiftschedule
    - Add field shift_id to employeeshiftschedule
    - Add field company_id to employeeshiftday
    - Add field company_id to employeeshift
    - Add field created_by to employeeshift
    - Add field days to employeeshift
    - Add field grace_time_id to employeeshift
    - Add field modified_by to employeeshift
    - Add field company_id to emaillog
    - Add field user_id to dynamicpagination
    - Add field company_id to dynamicemailconfiguration
    - Add field created_by to dynamicemailconfiguration
    - Add field modified_by to dynamicemailconfiguration
    - Add field user to driverviewed
    - Add field company_id to department
    - Add field created_by to department
    - Add field modified_by to department
    - Add field created_by to dashboardemployeecharts
    - Add field employee to dashboardemployeecharts
    - Add field modified_by to dashboardemployeecharts
    - Add field created_by to company
    - Add field modified_by to company
    - Add field company_id to biometricattendance
    - Add field announcement to announcementview
    - Add field user to announcementview
    - Add field announcement_id to announcementcomment
    - Add field created_by to announcementcomment
    - Add field employee_id to announcementcomment
    - Add field modified_by to announcementcomment
    - Add field attachments to announcement
    - Add field created_by to announcement
    - Add field department to announcement
    - Add field employees to announcement
    - Add field job_position to announcement
    - Add field modified_by to announcement
    - Alter unique_together for jobrole (1 constraint(s))
    - Alter unique_together for employeeshiftschedule (1 constraint(s))
    - Alter unique_together for company (1 constraint(s))
Migrations for 'employee':
  employee\migrations\0001_initial.py
    - Create model Actiontype
    - Create model BonusPoint
    - Create model Employee
    - Create model EmployeeTag
    - Create model EmployeeWorkInformation
    - Create model PolicyMultipleFile
    - Create model Policy
    - Create model NoteFiles
    - Create model HistoricalEmployeeWorkInformation
    - Create model HistoricalBonusPoint
    - Create model EmployeeNote
    - Create model EmployeeGeneralSetting
    - Create model EmployeeBankDetails
    - Create model DisciplinaryAction
    - Add field employee_id to bonuspoint
    - Add field modified_by to bonuspoint
    - Create constraint unique_badge_id on model employee
    - Alter unique_together for employee (1 constraint(s))
Migrations for 'helpdesk':
  helpdesk\migrations\0001_initial.py
    - Create model TicketType
    - Create model Ticket
    - Create model HistoricalTicket
    - Create model FAQCategory
    - Create model FAQ
    - Create model DepartmentManager
    - Create model Comment
    - Create model Attachment
Migrations for 'horilla_documents':
  horilla_documents\migrations\0001_initial.py
    - Create model DocumentRequest
    - Create model Document
Migrations for 'leave':
  leave\migrations\0001_initial.py
    - Create model AvailableLeave
    - Create model CompensatoryLeaveRequest
    - Create model LeaveAllocationRequest
    - Create model LeaveRequest
    - Create model LeaverequestFile
    - Create model RestrictLeave
    - Create model LeaveType
    - Create model LeaveRequestConditionApproval
    - Create model LeaverequestComment
    - Add field leave_type_id to leaverequest
    - Add field modified_by to leaverequest
    - Create model LeaveGeneralSetting
    - Create model LeaveallocationrequestComment
    - Add field leave_type_id to leaveallocationrequest
    - Add field modified_by to leaveallocationrequest
    - Create model Holiday
    - Create model HistoricalLeaveRequest
    - Create model HistoricalLeaveAllocationRequest
    - Create model HistoricalCompensatoryLeaveRequest
    - Create model HistoricalAvailableLeave
    - Create model CompensatoryLeaverequestComment
    - Add field leave_type_id to compensatoryleaverequest
    - Add field modified_by to compensatoryleaverequest
    - Add field leave_type_id to availableleave
    - Add field modified_by to availableleave
    - Create model CompanyLeave
    - Alter unique_together for availableleave (1 constraint(s))
Migrations for 'offboarding':
  offboarding\migrations\0001_initial.py
    - Create model EmployeeTask
    - Create model Offboarding
    - Create model OffboardingEmployee
    - Create model OffboardingStage
    - Create model ResignationLetter
    - Create model OffboardingTask
    - Create model OffboardingStageMultipleFile
    - Create model OffboardingNote
    - Create model OffboardingGeneralSetting
    - Add field stage_id to offboardingemployee
    - Create model HistoricalEmployeeTask
    - Create model ExitReason
    - Add field employee_id to employeetask
    - Add field modified_by to employeetask
    - Add field task_id to employeetask
    - Alter unique_together for employeetask (1 constraint(s))
Migrations for 'payroll':
  payroll\migrations\0001_initial.py
    - Create model Allowance
    - Create model Contract
    - Create model Deduction
    - Create model EncashmentGeneralSettings
    - Create model FilingStatus
    - Create model MultipleCondition
    - Create model OverrideAttendance
    - Create model OverrideLeaveRequest
    - Create model OverrideWorkInfo
    - Create model Reimbursement
    - Create model ReimbursementFile
    - Create model ReimbursementMultipleAttachment
    - Create model WorkRecord
    - Create model TaxBracket
    - Create model ReimbursementrequestComment
    - Add field other_attachments to reimbursement
    - Create model Payslip
    - Create model PayrollSettings
    - Create model PayrollGeneralSetting
    - Create model LoanAccount
    - Create model HistoricalPayslip
    - Create model HistoricalContract
    - Add field other_conditions to deduction
    - Add field specific_employees to deduction
    - Add field filing_status to contract
    - Add field job_position to contract
    - Add field job_role to contract
    - Add field modified_by to contract
    - Add field shift to contract
    - Add field work_type to contract
    - Add field other_conditions to allowance
    - Add field shift_id to allowance
    - Add field specific_employees to allowance
    - Add field work_type_id to allowance
    - Alter unique_together for contract (1 constraint(s))
    - Alter unique_together for allowance (1 constraint(s))
Migrations for 'pms':
  pms\migrations\0001_initial.py
    - Create model EmployeeKeyResult
    - Create model EmployeeObjective
    - Create model Feedback
    - Create model KeyResult
    - Create model Meetings
    - Create model Question
    - Create model QuestionTemplate
    - Create model QuestionOptions
    - Add field template_id to question
    - Create model Period
    - Create model Objective
    - Create model MeetingsAnswer
    - Add field question_template to meetings
    - Create model KeyResultFeedback
    - Create model HistoricalObjective
    - Create model HistoricalKeyResult
    - Create model HistoricalEmployeeObjective
    - Create model HistoricalEmployeeKeyResult
    - Create model HistoricalComment
    - Add field question_template_id to feedback
    - Add field subordinate_id to feedback
    - Add field key_result_id to employeeobjective
    - Add field modified_by to employeeobjective
    - Add field objective_id to employeeobjective
    - Add field employee_objective_id to employeekeyresult
    - Add field key_result_id to employeekeyresult
    - Create model Comment
    - Create model Answer
    - Create model AnonymousFeedback
Migrations for 'recruitment':
  recruitment\migrations\0001_initial.py
    - Create model Candidate
    - Create model Recruitment
    - Create model SkillZone
    - Create model Stage
    - Create model StageFiles
    - Create model SurveyTemplate
    - Create model StageNote
    - Create model RejectReason
    - Create model RejectedCandidate
    - Create model RecruitmentSurveyAnswer
    - Create model RecruitmentSurvey
    - Create model RecruitmentMailTemplate
    - Create model RecruitmentGeneralSetting
    - Add field survey_templates to recruitment
    - Create model QuestionOrdering
    - Create model InterviewSchedule
    - Create model HistoricalRejectedCandidate
    - Create model HistoricalCandidate
    - Add field recruitment_id to candidate
    - Add field referral to candidate
    - Add field stage_id to candidate
    - Create model SkillZoneCandidate
    - Alter unique_together for recruitment (2 constraint(s))
    - Create model CandidateRating
    - Alter unique_together for candidate (1 constraint(s))
Migrations for 'onboarding':
  onboarding\migrations\0001_initial.py
    - Create model CandidateTask
    - Create model OnboardingStage
    - Create model OnboardingTask
    - Create model OnboardingPortal
    - Create model HistoricalCandidateTask
    - Add field onboarding_task_id to candidatetask
    - Add field stage_id to candidatetask
    - Create model CandidateStage
Migrations for 'notifications':
  notifications\migrations\0001_initial.py
    - Create model Notification

C:\Horilla\horilla>python manage.py migrate
System check identified some issues:

WARNINGS:
employee.Employee: (models.W036) MySQL does not support unique constraints with conditions.
        HINT: A constraint won't be created. Silence this warning if you don't care about it.
Operations to perform:
  Apply all migrations: admin, asset, attendance, auditlog, auth, base, contenttypes, django_apscheduler, employee, helpdesk, horilla_audit, horilla_documents, leave, notifications, offboarding, onboarding, payroll, pms, recruitment, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying horilla_audit.0001_initial... OK
  Applying base.0001_initial... OK
  Applying employee.0001_initial... OK
  Applying asset.0001_initial... OK
  Applying asset.0002_initial... OK
  Applying attendance.0001_initial... OK
  Applying leave.0001_initial... OK
  Applying attendance.0002_initial... OK
  Applying auditlog.0001_initial... OK
  Applying auditlog.0002_auto_support_long_primary_keys... OK
  Applying auditlog.0003_logentry_remote_addr... OK
  Applying auditlog.0004_logentry_detailed_object_repr... OK
  Applying auditlog.0005_logentry_additional_data_verbose_name... OK
  Applying auditlog.0006_object_pk_index... OK
  Applying auditlog.0007_object_pk_type... OK
  Applying auditlog.0008_action_index... OK
  Applying auditlog.0009_alter_logentry_additional_data... OK
  Applying auditlog.0010_alter_logentry_timestamp... OK
  Applying auditlog.0011_logentry_serialized_data... OK
  Applying auditlog.0012_add_logentry_action_access... OK
  Applying auditlog.0013_alter_logentry_timestamp... OK
  Applying auditlog.0014_logentry_cid... OK
  Applying auditlog.0015_alter_logentry_changes... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying base.0002_initial...Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
MySQLdb.OperationalError: (1170, "BLOB/TEXT column 'address' used in key specification without a key length")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Horilla\horilla\manage.py", line 22, in <module>
    main()
  File "C:\Horilla\horilla\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 458, in execute
    output = self.handle(*args, **options)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 106, in wrapper
    res = handle_func(*args, **kwargs)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\commands\migrate.py", line 356, in handle
    post_migrate_state = executor.migrate(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\migrations\executor.py", line 135, in migrate
    state = self._migrate_all_forwards(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\migrations\executor.py", line 167, in _migrate_all_forwards
    state = self.apply_migration(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\migrations\executor.py", line 252, in apply_migration
    state = migration.apply(state, schema_editor)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\migrations\migration.py", line 132, in apply
    operation.database_forwards(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\migrations\operations\models.py", line 659, in database_forwards
    alter_together(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\base\schema.py", line 563, in alter_unique_together
    self.execute(self._create_unique_sql(model, fields))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\base\schema.py", line 201, in execute
    cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 102, in execute
    return super().execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
django.db.utils.OperationalError: (1170, "BLOB/TEXT column 'address' used in key specification without a key length")

C:\Horilla\horilla>python manage.py createhorillauser
Enter first name: Rohit
Enter last name: Bale
Enter username: rbale
Enter password: rbale
Enter email: rbale0831@gmail.com
Enter phone number: 9999999999
Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\fields\related_descriptors.py", line 473, in __get__
    rel_obj = self.related.get_cached_value(instance)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\fields\mixins.py", line 15, in get_cached_value
    return instance._state.fields_cache[cache_name]
KeyError: 'offboardingemployee'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
MySQLdb.ProgrammingError: (1146, "Table 'localhorilla.offboarding_offboardingemployee' doesn't exist")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Horilla\horilla\base\management\commands\createhorillauser.py", line 50, in handle
    employee.save()
  File "C:\Horilla\horilla\employee\models.py", line 413, in save
    super().save(*args, **kwargs)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 814, in save
    self.save_base(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 892, in save_base
    post_save.send(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\dispatch\dispatcher.py", line 176, in send
    return [
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\dispatch\dispatcher.py", line 177, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\receivers.py", line 27, in wrapper
    signal_handler(*args, **kwargs)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\receivers.py", line 40, in log_create
    _create_log_entry(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\receivers.py", line 146, in _create_log_entry
    raise error
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\receivers.py", line 119, in _create_log_entry
    changes = model_instance_diff(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\diff.py", line 186, in model_instance_diff
    new_value = get_field_value(new, field)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\diff.py", line 84, in get_field_value
    value = smart_str(getattr(obj, field.name, None))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\fields\related_descriptors.py", line 481, in __get__
    rel_obj = self.get_queryset(instance=instance).get(**filter_args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 633, in get
    num = len(clone)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 380, in __len__
    self._fetch_all()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 1881, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 91, in __iter__
    results = compiler.execute_sql(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\sql\compiler.py", line 1562, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 102, in execute
    return super().execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
django.db.utils.ProgrammingError: (1146, "Table 'localhorilla.offboarding_offboardingemployee' doesn't exist")

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
MySQLdb.ProgrammingError: (1146, "Table 'localhorilla.notifications_notification' doesn't exist")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Horilla\horilla\manage.py", line 22, in <module>
    main()
  File "C:\Horilla\horilla\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 458, in execute
    output = self.handle(*args, **options)
  File "C:\Horilla\horilla\base\management\commands\createhorillauser.py", line 62, in handle
    user.delete()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 1131, in delete
    collector.collect([self], keep_parents=keep_parents)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\deletion.py", line 348, in collect
    if getattr(on_delete, "lazy_sub_objs", False) or sub_objs:
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 412, in __bool__
    self._fetch_all()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 1881, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 91, in __iter__
    results = compiler.execute_sql(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\sql\compiler.py", line 1562, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 102, in execute
    return super().execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
django.db.utils.ProgrammingError: (1146, "Table 'localhorilla.notifications_notification' doesn't exist")

C:\Horilla\horilla>python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 19 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): base, django_apscheduler, helpdesk, horilla_documents, notifications, offboarding, onboarding, payroll, pms, recruitment, sessions.
Run 'python manage.py migrate' to apply them.
June 01, 2024 - 01:14:40
Django version 4.2.13, using settings 'horilla.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

Internal Server Error: /
Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\sessions\backends\base.py", line 187, in _get_session
    return self._session_cache
AttributeError: 'SessionStore' object has no attribute '_session_cache'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
MySQLdb.ProgrammingError: (1146, "Table 'localhorilla.django_session' doesn't exist")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\middleware.py", line 48, in __call__
    user = self._get_actor(request)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\auditlog\middleware.py", line 42, in _get_actor
    if isinstance(user, get_user_model()) and user.is_authenticated:
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\functional.py", line 295, in __getattribute__
    value = super().__getattribute__(name)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\functional.py", line 266, in inner
    self._setup()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\functional.py", line 419, in _setup
    self._wrapped = self._setupfunc()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\auth\middleware.py", line 25, in <lambda>
    request.user = SimpleLazyObject(lambda: get_user(request))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\auth\middleware.py", line 11, in get_user
    request._cached_user = auth.get_user(request)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\auth\__init__.py", line 191, in get_user
    user_id = _get_user_session_key(request)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\auth\__init__.py", line 60, in _get_user_session_key
    return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\sessions\backends\base.py", line 53, in __getitem__
    return self._session[key]
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\sessions\backends\base.py", line 192, in _get_session
    self._session_cache = self.load()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\sessions\backends\db.py", line 42, in load
    s = self._get_session_from_db()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\sessions\backends\db.py", line 32, in _get_session_from_db
    return self.model.objects.get(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 633, in get
    num = len(clone)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 380, in __len__
    self._fetch_all()
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 1881, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 91, in __iter__
    results = compiler.execute_sql(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\sql\compiler.py", line 1562, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 102, in execute
    return super().execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
django.db.utils.ProgrammingError: (1146, "Table 'localhorilla.django_session' doesn't exist")
[01/Jun/2024 01:14:42] "GET / HTTP/1.1" 500 208770

Screenshots

Screenshot after the application starts

image

image

image

image

image

image

Environment

horilla-opensource commented 2 months ago

HI @rbale0831 , Can you try out a postgresql database. The MySQL database has been recently failing for some reasons and the team is working on it. We suggest to move to a psql database for better performance.

With Regards, Team Horilla

rbale0831 commented 2 months ago

Hello @horilla-opensource, I have solved the issue for the base module but was not able to solve it for the payroll module. when I used migrate it throws this error

MySQLdb.OperationalError: (1071, 'Specified key was too long; max key length is 3072 bytes')

can you help me in resolve this error

horilla-opensource commented 2 months ago

Hi @rbale0831 , Can you try again by setting the encoding type for the database to utf-8?

ALTER DATABASE '<databasename>' CHARACTER SET utf8;

With Regards, Team Horilla

rbale0831 commented 2 months ago

Hello @horilla-opensource, I have created fresh database with utf8 and try to execute same error

Screenshot 2024-06-03 114008

Screenshot 2024-06-03 113851

MySQLdb.OperationalError: (1071, 'Specified key was too long; max key length is 3072 bytes')

horilla-opensource commented 2 months ago

Can you try with utf8mb4 format ?

rbale0831 commented 2 months ago

Yes, I have tried using it, no use again same error MySQLdb.OperationalError: (1071, 'Specified key was too long; max key length is 3072 bytes')

Screenshot 2024-06-03 120111 Screenshot 2024-06-03 120057

horilla-opensource commented 2 months ago

In which field is this error showing up?

rbale0831 commented 2 months ago
Applying payroll.0001_initial...Traceback (most recent call last):
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\mysql\base.py", line 75, in execute
    return self.cursor.execute(query, args)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 179, in execute
    res = self._query(mogrified_query)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\cursors.py", line 330, in _query
    db.query(q)
  File "C:\Users\RohitGangarajamBale\AppData\Local\Programs\Python\Python310\lib\site-packages\MySQLdb\connections.py", line 261, in query
    _mysql.connection.query(self, query)
MySQLdb.OperationalError: (1071, 'Specified key was too long; max key length is 3072 bytes')

in this field

horilla-opensource commented 2 months ago

Can you share the contents of this file : payroll.0001_initial*.py ?

rbale0831 commented 2 months ago
"""
models.py
Used to register models
"""

import calendar
from datetime import date, datetime, timedelta

from django import forms
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.signals import post_save, pre_delete, pre_save
from django.dispatch import receiver
from django.http import QueryDict
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from asset.models import Asset
from attendance.models import Attendance, strtime_seconds, validate_time_format
from base import thread_local_middleware
from base.horilla_company_manager import HorillaCompanyManager
from base.models import (
    Company,
    Department,
    EmployeeShift,
    JobPosition,
    JobRole,
    WorkType,
)
from employee.models import BonusPoint, Employee, EmployeeWorkInformation
from horilla.models import HorillaModel
from horilla_audit.models import HorillaAuditInfo, HorillaAuditLog
from leave.models import LeaveRequest, LeaveType

# Create your models here.

def min_zero(value):
    """
    The minimum value zero validation method
    """
    if value < 0:
        raise ValidationError(_("Value must be greater than zero"))

def get_date_range(start_date, end_date):
    """
    Returns a list of all dates within a given date range.

    Args:
        start_date (date): The start date of the range.
        end_date (date): The end date of the range.

    Returns:
        list: A list of date objects representing all dates within the range.

    Example:
        start_date = date(2023, 1, 1)
        end_date = date(2023, 1, 10)
        date_range = get_date_range(start_date, end_date)
        for date_obj in date_range:
            print(date_obj)
    """
    date_list = []
    delta = end_date - start_date

    for i in range(delta.days + 1):
        current_date = start_date + timedelta(days=i)
        date_list.append(current_date)

    return date_list

class FilingStatus(HorillaModel):
    """
    FilingStatus model
    """

    based_on_choice = [
        ("basic_pay", _("Basic Pay")),
        ("gross_pay", _("Gross Pay")),
        ("taxable_gross_pay", _("Taxable Gross Pay")),
    ]
    filing_status = models.CharField(
        max_length=30,
        blank=False,
        verbose_name=_("Filing status"),
    )
    based_on = models.CharField(
        max_length=255,
        choices=based_on_choice,
        null=False,
        blank=False,
        default="taxable_gross_pay",
        verbose_name=_("Based on"),
    )
    description = models.TextField(
        blank=True,
        verbose_name=_("Description"),
        max_length=255,
    )
    company_id = models.ForeignKey(
        Company, null=True, editable=False, on_delete=models.PROTECT
    )
    objects = HorillaCompanyManager()

    def __str__(self) -> str:
        return str(self.filing_status)

class Contract(HorillaModel):
    """
    Contract Model
    """

    COMPENSATION_CHOICES = (
        ("salary", _("Salary")),
        ("hourly", _("Hourly")),
        ("commission", _("Commission")),
    )

    PAY_FREQUENCY_CHOICES = (
        ("weekly", _("Weekly")),
        ("monthly", _("Monthly")),
        ("semi_monthly", _("Semi-Monthly")),
    )
    WAGE_CHOICES = (
        ("hourly", _("Hourly")),
        ("daily", _("Daily")),
        ("monthly", _("Monthly")),
    )
    CONTRACT_STATUS_CHOICES = (
        ("draft", _("Draft")),
        ("active", _("Active")),
        ("expired", _("Expired")),
        ("terminated", _("Terminated")),
    )
    try:
        # Here would be not filing status model at the initial/empty db
        FILING_STATUS_CHOICES = [("", _("None"))] + list(
            FilingStatus.objects.values_list("id", "filing_status")
        )
    except:
        pass

    contract_name = models.CharField(
        max_length=250, help_text=_("Contract Title."), verbose_name=_("Contract")
    )
    employee_id = models.ForeignKey(
        Employee,
        on_delete=models.PROTECT,
        related_name="contract_set",
        verbose_name=_("Employee"),
    )
    contract_start_date = models.DateField(verbose_name=_("Start Date"))
    contract_end_date = models.DateField(
        null=True, blank=True, verbose_name=_("End Date")
    )
    wage_type = models.CharField(
        choices=WAGE_CHOICES,
        max_length=250,
        default="monthly",
        verbose_name=_("Wage Type"),
    )
    pay_frequency = models.CharField(
        max_length=20,
        null=True,
        choices=PAY_FREQUENCY_CHOICES,
        default="monthly",
        verbose_name=_("Pay Frequency"),
    )
    wage = models.FloatField(verbose_name=_("Basic Salary"), null=True, default=0)
    filing_status = models.ForeignKey(
        FilingStatus,
        on_delete=models.PROTECT,
        related_name="contracts",
        null=True,
        blank=True,
        verbose_name=_("Filing Status"),
    )
    contract_status = models.CharField(
        choices=CONTRACT_STATUS_CHOICES,
        max_length=250,
        default="draft",
        verbose_name=_("Status"),
    )
    department = models.ForeignKey(
        Department,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name="contracts",
        verbose_name=_("Department"),
    )
    job_position = models.ForeignKey(
        JobPosition,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name="contracts",
        verbose_name=_("Job Position"),
    )
    job_role = models.ForeignKey(
        JobRole,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name="contracts",
        verbose_name=_("Job Role"),
    )
    shift = models.ForeignKey(
        EmployeeShift,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name="contracts",
        verbose_name=_("Shift"),
    )
    work_type = models.ForeignKey(
        WorkType,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name="contracts",
        verbose_name=_("Work Type"),
    )
    notice_period_in_days = models.IntegerField(
        default=30,
        help_text=_("Notice period in total days."),
        validators=[min_zero],
        verbose_name=_("Notice Period"),
    )
    contract_document = models.FileField(upload_to="uploads/", null=True, blank=True)
    deduct_leave_from_basic_pay = models.BooleanField(
        default=True,
        verbose_name=_("Deduct From Basic Pay"),
        help_text=_("Deduct the leave amount from basic pay."),
    )
    calculate_daily_leave_amount = models.BooleanField(
        default=True,
        verbose_name=_("Calculate Daily Leave Amount"),
        help_text=_(
            "Leave amount will be calculated by dividing the basic pay by number of working days."
        ),
    )
    deduction_for_one_leave_amount = models.FloatField(
        null=True,
        blank=True,
        default=0,
        verbose_name=_("Deduction For One Leave Amount"),
    )

    note = models.TextField(null=True, blank=True, max_length=255)
    history = HorillaAuditLog(
        related_name="history_set",
        bases=[
            HorillaAuditInfo,
        ],
    )

    objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")

    def __str__(self) -> str:
        return f"{self.contract_name} -{self.contract_start_date} - {self.contract_end_date}"

    def clean(self):
        if self.contract_end_date is not None:
            if self.contract_end_date < self.contract_start_date:
                raise ValidationError(
                    {"contract_end_date": _("End date must be greater than start date")}
                )
        if (
            self.contract_status == "active"
            and Contract.objects.filter(
                employee_id=self.employee_id, contract_status="active"
            )
            .exclude(id=self.pk)
            .count()
            >= 1
        ):
            raise forms.ValidationError(
                _("An active contract already exists for this employee.")
            )
        if (
            self.contract_status == "draft"
            and Contract.objects.filter(
                employee_id=self.employee_id, contract_status="draft"
            )
            .exclude(id=self.pk)
            .count()
            >= 1
        ):
            raise forms.ValidationError(
                _("A draft contract already exists for this employee.")
            )

        if self.wage_type in ["daily", "monthly"]:
            if not self.calculate_daily_leave_amount:
                if self.deduction_for_one_leave_amount is None:
                    raise ValidationError(
                        {"deduction_for_one_leave_amount": _("This field is required")}
                    )

    def save(self, *args, **kwargs):
        if EmployeeWorkInformation.objects.filter(
            employee_id=self.employee_id
        ).exists():
            if self.department is None:
                self.department = self.employee_id.employee_work_info.department_id

            if self.job_position is None:
                self.job_position = self.employee_id.employee_work_info.job_position_id

            if self.job_role is None:
                self.job_role = self.employee_id.employee_work_info.job_role_id

            if self.work_type is None:
                self.work_type = self.employee_id.employee_work_info.work_type_id

            if self.shift is None:
                self.shift = self.employee_id.employee_work_info.shift_id
        if self.contract_end_date is not None and self.contract_end_date < date.today():
            self.contract_status = "expired"
        if (
            self.contract_status == "active"
            and Contract.objects.filter(
                employee_id=self.employee_id, contract_status="active"
            )
            .exclude(id=self.id)
            .count()
            >= 1
        ):
            raise forms.ValidationError(
                _("An active contract already exists for this employee.")
            )

        if (
            self.contract_status == "draft"
            and Contract.objects.filter(
                employee_id=self.employee_id, contract_status="draft"
            )
            .exclude(id=self.pk)
            .count()
            >= 1
        ):
            raise forms.ValidationError(
                _("A draft contract already exists for this employee.")
            )

        super().save(*args, **kwargs)
        return self

    class Meta:
        """
        Meta class to add additional options
        """

        unique_together = ["employee_id", "contract_start_date", "contract_end_date"]

class WorkRecord(models.Model):
    """
    WorkRecord Model
    """

    choices = [
        ("FDP", _("Present")),
        ("HDP", _("Half Day Present")),
        ("ABS", _("Absent")),
        ("HD", _("Holiday/Company Leave")),
        ("CONF", _("Conflict")),
        ("DFT", _("Draft")),
    ]

    record_name = models.CharField(max_length=250, null=True, blank=True)
    work_record_type = models.CharField(max_length=5, null=True, choices=choices)
    employee_id = models.ForeignKey(
        Employee, on_delete=models.PROTECT, verbose_name=_("Employee")
    )
    date = models.DateField(null=True, blank=True)
    at_work = models.CharField(
        null=True,
        blank=True,
        validators=[
            validate_time_format,
        ],
        default="00:00",
        max_length=5,
    )
    min_hour = models.CharField(
        null=True,
        blank=True,
        validators=[
            validate_time_format,
        ],
        default="00:00",
        max_length=5,
    )
    at_work_second = models.IntegerField(null=True, blank=True, default=0)
    min_hour_second = models.IntegerField(null=True, blank=True, default=0)
    note = models.TextField(max_length=255)
    message = models.CharField(max_length=30, null=True, blank=True)
    is_attendance_record = models.BooleanField(default=False)
    is_leave_record = models.BooleanField(default=False)
    day_percentage = models.FloatField(default=0)
    last_update = models.DateTimeField(null=True, blank=True)
    objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")

    def save(self, *args, **kwargs):
        self.last_update = timezone.now()

        super().save(*args, **kwargs)

    def clean(self):
        super().clean()
        if not 0.0 <= self.day_percentage <= 1.0:
            raise ValidationError(_("Day percentage must be between 0.0 and 1.0"))

    def __str__(self):
        return (
            self.record_name
            if self.record_name is not None
            else f"{self.work_record_type}-{self.date}"
        )

class OverrideAttendance(Attendance):
    """
    Class to override Attendance model save method
    """

    # Additional fields and methods specific to AnotherModel
    @receiver(post_save, sender=Attendance)
    def attendance_post_save(sender, instance, **kwargs):
        """
        Overriding Attendance model save method
        """
        if instance.first_save:
            min_hour_second = strtime_seconds(instance.minimum_hour)
            at_work_second = strtime_seconds(instance.attendance_worked_hour)

            status = "FDP" if instance.at_work_second >= min_hour_second else "HDP"

            status = "CONF" if instance.attendance_validated is False else status
            message = (
                _("Validate the attendance") if status == "CONF" else _("Validated")
            )

            message = (
                _("Incomplete minimum hour")
                if status == "HDP" and min_hour_second > at_work_second
                else message
            )
            work_record = WorkRecord.objects.filter(
                date=instance.attendance_date,
                is_attendance_record=True,
                employee_id=instance.employee_id,
            )
            work_record = (
                WorkRecord()
                if not WorkRecord.objects.filter(
                    date=instance.attendance_date,
                    employee_id=instance.employee_id,
                ).exists()
                else WorkRecord.objects.filter(
                    date=instance.attendance_date,
                    employee_id=instance.employee_id,
                ).first()
            )
            work_record.employee_id = instance.employee_id
            work_record.date = instance.attendance_date
            work_record.at_work = instance.attendance_worked_hour
            work_record.min_hour = instance.minimum_hour
            work_record.min_hour_second = min_hour_second
            work_record.at_work_second = at_work_second
            work_record.work_record_type = status
            work_record.message = message
            work_record.is_attendance_record = True
            if instance.attendance_validated:
                work_record.day_percentage = (
                    1.00 if at_work_second > min_hour_second / 2 else 0.50
                )
            work_record.save()

            if status == "HDP" and work_record.is_leave_record:
                message = _("Half day leave")

            if status == "FDP":
                message = _("Present")

            work_record.message = message
            work_record.save()

            message = work_record.message
            status = work_record.work_record_type
            if not instance.attendance_clock_out:
                status = "FDP"
                message = _("Currently working")
            work_record.message = message
            work_record.work_record_type = status
            work_record.save()

    @receiver(pre_delete, sender=Attendance)
    def attendance_pre_delete(sender, instance, **_kwargs):
        """
        Overriding Attendance model delete method
        """
        # Perform any actions before deleting the instance
        # ...
        WorkRecord.objects.filter(
            employee_id=instance.employee_id,
            is_attendance_record=True,
            date=instance.attendance_date,
        ).delete()

class OverrideLeaveRequest(LeaveRequest):
    """
    Class to override Attendance model save method
    """

    # Additional fields and methods specific to AnotherModel
    @receiver(pre_save, sender=LeaveRequest)
    def leaverequest_pre_save(sender, instance, **_kwargs):
        """
        Overriding LeaveRequest model save method
        """
        if (
            instance.start_date == instance.end_date
            and instance.end_date_breakdown != instance.start_date_breakdown
        ):
            instance.end_date_breakdown = instance.start_date_breakdown
            super(LeaveRequest, instance).save()

        period_dates = get_date_range(instance.start_date, instance.end_date)
        if instance.status == "approved":
            for date in period_dates:
                try:
                    work_entry = (
                        WorkRecord.objects.filter(
                            date=date,
                            employee_id=instance.employee_id,
                        )
                        if WorkRecord.objects.filter(
                            date=date,
                            employee_id=instance.employee_id,
                        ).exists()
                        else WorkRecord()
                    )
                    work_entry.employee_id = instance.employee_id
                    work_entry.is_leave_record = True
                    work_entry.day_percentage = (
                        0.50
                        if instance.start_date == date
                        and instance.start_date_breakdown == "first_half"
                        or instance.end_date == date
                        and instance.end_date_breakdown == "second_half"
                        else 0.00
                    )
                    # scheduler task to validate the conflict entry for half day if they
                    # take half day leave is when they mark the attendance.
                    status = (
                        "CONF"
                        if instance.start_date == date
                        and instance.start_date_breakdown == "first_half"
                        or instance.end_date == date
                        and instance.end_date_breakdown == "second_half"
                        else "ABS"
                    )
                    work_entry.work_record_type = status
                    work_entry.date = date
                    work_entry.message = (
                        "Absent"
                        if status == "ABS"
                        else _("Half day Attendance need to validate")
                    )
                    work_entry.save()
                except:
                    pass

        else:
            for date in period_dates:
                WorkRecord.objects.filter(
                    is_leave_record=True, date=date, employee_id=instance.employee_id
                ).delete()

class OverrideWorkInfo(EmployeeWorkInformation):
    """
    This class is to override the Model default methods
    """

    @receiver(pre_save, sender=EmployeeWorkInformation)
    def employeeworkinformation_pre_save(sender, instance, **_kwargs):
        """
        This method is used to override the save method for EmployeeWorkInformation Model
        """
        active_employee = (
            instance.employee_id if instance.employee_id.is_active == True else None
        )
        if active_employee is not None:
            contract_exists = active_employee.contract_set.exists()
            if not contract_exists:
                contract = Contract()
                contract.contract_name = f"{active_employee}'s Contract"
                contract.employee_id = active_employee
                contract.contract_start_date = datetime.today()
                contract.wage = (
                    instance.basic_salary if instance.basic_salary is not None else 0
                )
                contract.save()

# Create your models here.
def rate_validator(value):
    """
    Percentage validator
    """
    if value < 0:
        raise ValidationError(_("Rate must be greater than 0"))
    if value > 100:
        raise ValidationError(_("Rate must be less than 100"))

CONDITION_CHOICE = [
    ("equal", _("Equal (==)")),
    ("notequal", _("Not Equal (!=)")),
    ("lt", _("Less Than (<)")),
    ("gt", _("Greater Than (>)")),
    ("le", _("Less Than or Equal To (<=)")),
    ("ge", _("Greater Than or Equal To (>=)")),
    ("icontains", _("Contains")),
]
IF_CONDITION_CHOICE = [
    ("equal", _("Equal (==)")),
    ("notequal", _("Not Equal (!=)")),
    ("lt", _("Less Than (<)")),
    ("gt", _("Greater Than (>)")),
    ("le", _("Less Than or Equal To (<=)")),
    ("ge", _("Greater Than or Equal To (>=)")),
]
FIELD_CHOICE = [
    ("children", _("Children")),
    ("marital_status", _("Marital Status")),
    ("experience", _("Experience")),
    ("employee_work_info__experience", _("Company Experience")),
    ("gender", _("Gender")),
    ("country", _("Country")),
    ("state", _("State")),
    ("contract_set__pay_frequency", _("Pay Frequency")),
    ("contract_set__wage_type", _("Wage Type")),
    ("contract_set__department__department", _("Department on Contract")),
]

class MultipleCondition(models.Model):
    """
    MultipleCondition Model
    """

    field = models.CharField(
        max_length=255,
    )
    condition = models.CharField(
        max_length=255, choices=CONDITION_CHOICE, null=True, blank=True
    )
    value = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        help_text=_("The value must be like the data stored in the database"),
    )

class Allowance(HorillaModel):
    """
    Allowance model
    """

    exceed_choice = [
        ("ignore", _("Exclude the allowance")),
        ("max_amount", _("Provide max amount")),
    ]

    based_on_choice = [
        ("basic_pay", _("Basic Pay")),
        ("attendance", _("Attendance")),
        ("shift_id", _("Shift")),
        ("overtime", _("Overtime")),
        ("work_type_id", _("Work Type")),
    ]

    if_condition_choice = [
        ("basic_pay", _("Basic Pay")),
    ]
    title = models.CharField(
        max_length=255, null=False, blank=False, help_text=_("Title of the allowance")
    )
    one_time_date = models.DateField(
        null=True,
        blank=True,
        help_text=_(
            "The one-time allowance in which the allowance will apply to the payslips \
            if the date between the payslip period"
        ),
    )
    include_active_employees = models.BooleanField(
        default=False,
        verbose_name=_("Include all active employees"),
        help_text=_("Target allowance to all active employees in the company"),
    )
    specific_employees = models.ManyToManyField(
        Employee,
        verbose_name=_("Employees Specific"),
        blank=True,
        related_name="allowance_specific",
        help_text=_("Target allowance to the specific employees"),
    )
    exclude_employees = models.ManyToManyField(
        Employee,
        verbose_name=_("Exclude Employees"),
        related_name="allowance_excluded",
        blank=True,
        help_text=_(
            "To ignore the allowance to the employees when target them by all employees \
            or through condition-based"
        ),
    )
    is_taxable = models.BooleanField(
        default=True,
        help_text=_("This field is used to calculate the taxable allowances"),
    )
    is_condition_based = models.BooleanField(
        default=False,
        help_text=_(
            "This field is used to target allowance \
        to the specific employees when the condition satisfies with the employee's information"
        ),
    )
    # If condition based
    field = models.CharField(
        max_length=255,
        choices=FIELD_CHOICE,
        null=True,
        blank=True,
        help_text=_("The related field of the employees"),
    )
    condition = models.CharField(
        max_length=255, choices=CONDITION_CHOICE, null=True, blank=True
    )
    value = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        help_text=_("The value must be like the data stored in the database"),
    )

    is_fixed = models.BooleanField(
        default=True, help_text=_("To specify, the allowance is fixed or not")
    )
    amount = models.FloatField(
        null=True,
        blank=True,
        validators=[min_zero],
        help_text=_("Fixed amount for this allowance"),
    )
    # If is fixed is false
    based_on = models.CharField(
        max_length=255,
        default="basic_pay",
        choices=based_on_choice,
        null=True,
        blank=True,
        help_text=_(
            "If the allowance is not fixed then specifies how the allowance provided"
        ),
    )
    rate = models.FloatField(
        null=True,
        blank=True,
        validators=[
            rate_validator,
        ],
        help_text=_("The percentage of based on"),
    )
    # If based on attendance
    per_attendance_fixed_amount = models.FloatField(
        null=True,
        blank=True,
        default=0.00,
        validators=[min_zero],
        help_text=_("The attendance fixed amount for one validated attendance"),
    )
    # If based on shift
    shift_id = models.ForeignKey(
        EmployeeShift,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        verbose_name=_("Shift"),
    )
    shift_per_attendance_amount = models.FloatField(
        null=True,
        default=0.00,
        blank=True,
        validators=[min_zero],
        help_text=_("The fixed amount for one validated attendance with that shift"),
    )
    amount_per_one_hr = models.FloatField(
        null=True,
        default=0.00,
        blank=True,
        validators=[min_zero],
        help_text=_(
            "The fixed amount for one hour overtime that are validated \
            and approved the overtime attendance"
        ),
    )
    work_type_id = models.ForeignKey(
        WorkType,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        verbose_name=_("Work Type"),
    )
    work_type_per_attendance_amount = models.FloatField(
        null=True,
        default=0.00,
        blank=True,
        validators=[min_zero],
        help_text=_(
            "The fixed amount for one validated attendance with that work type"
        ),
    )
    # for apply only
    has_max_limit = models.BooleanField(
        default=False,
        verbose_name=_("Has max limit for allowance"),
        help_text=_("Limit the allowance amount"),
    )
    maximum_amount = models.FloatField(
        null=True,
        blank=True,
        validators=[min_zero],
        help_text=_("The maximum amount for the allowance"),
    )
    maximum_unit = models.CharField(
        max_length=20,
        null=True,
        default="month_working_days",
        choices=[
            (
                "month_working_days",
                _("For working days on month"),
            ),
            # ("monthly_working_days", "For working days on month"),
        ],
        help_text="The maximum amount for ?",
    )
    if_choice = models.CharField(
        max_length=10,
        choices=if_condition_choice,
        default="basic_pay",
        help_text=_("The pay head for the if condition"),
    )
    if_condition = models.CharField(
        max_length=10,
        choices=IF_CONDITION_CHOICE,
        default="gt",
        help_text=_("Apply for those, if the pay-head conditions satisfy"),
    )
    if_amount = models.FloatField(
        default=0.00, help_text=_("The amount of the pay-head")
    )
    company_id = models.ForeignKey(
        Company, null=True, editable=False, on_delete=models.PROTECT
    )
    only_show_under_employee = models.BooleanField(default=False, editable=False)
    is_loan = models.BooleanField(default=False, editable=False)
    objects = HorillaCompanyManager()
    other_conditions = models.ManyToManyField(
        MultipleCondition, blank=True, editable=False
    )

    class Meta:
        """
        Meta class for additional options
        """

        unique_together = [
            "title",
            "is_taxable",
            "is_condition_based",
            "field",
            "condition",
            "value",
            "is_fixed",
            "amount",
            "based_on",
            "rate",
            "per_attendance_fixed_amount",
            "shift_id",
            "shift_per_attendance_amount",
            "amount_per_one_hr",
            "work_type_id",
            "work_type_per_attendance_amount",
        ]
        verbose_name = _("Allowance")

    def reset_based_on(self):
        """Reset the this fields when is_fixed attribute is true"""
        attributes_to_reset = [
            "based_on",
            "rate",
            "per_attendance_fixed_amount",
            "shift_id",
            "shift_per_attendance_amount",
            "amount_per_one_hr",
            "work_type_id",
            "work_type_per_attendance_amount",
            "maximum_amount",
        ]
        for attribute in attributes_to_reset:
            setattr(self, attribute, None)
        self.has_max_limit = False

    def clean(self):
        super().clean()
        self.clean_fixed_attributes()
        if not self.is_condition_based:
            self.field = None
            self.condition = None
            self.value = None
        if not self.is_fixed:
            if not self.based_on:
                raise ValidationError(
                    _(
                        "If the 'Is fixed' field is disabled, the 'Based on' field is required."
                    )
                )
        if not self.is_fixed and self.based_on and self.based_on == "basic_pay":
            if not self.rate:
                raise ValidationError(
                    _("Rate must be specified for allowances based on basic pay.")
                )
        if self.is_condition_based:
            if not self.field or not self.value or not self.condition:
                raise ValidationError(
                    _(
                        "If condition based, all fields (field, value, condition) must be filled."
                    )
                )
        if self.based_on == "attendance" and not self.per_attendance_fixed_amount:
            raise ValidationError(
                {
                    "based_on": _(
                        "If based on is attendance, \
                        then per attendance fixed amount must be filled."
                    )
                }
            )
        if self.based_on == "shift_id" and not self.shift_id:
            raise ValidationError(_("If based on is shift, then shift must be filled."))
        if self.based_on == "work_type_id" and not self.work_type_id:
            raise ValidationError(
                _("If based on is work type, then work type must be filled.")
            )

        if self.is_fixed and self.amount < 0:
            raise ValidationError({"amount": _("Amount should be greater than zero.")})

        if self.has_max_limit and self.maximum_amount is None:
            raise ValidationError({"maximum_amount": _("This field is required")})

        if not self.has_max_limit:
            self.maximum_amount = None

    def clean_fixed_attributes(self):
        """Clean the amount field and trigger the reset_based_on function based on the condition"""
        if not self.is_fixed:
            self.amount = None
        if self.is_fixed:
            if self.amount is None:
                raise ValidationError({"amount": _("This field is required")})
            self.reset_based_on()

    def __str__(self) -> str:
        return str(self.title)

    def save(self):
        super().save()
        if (
            not self.include_active_employees
            and not self.specific_employees.first()
            and not self.is_condition_based
        ):
            self.include_active_employees = True
            super().save()

class Deduction(HorillaModel):
    """
    Deduction model
    """

    if_condition_choice = [
        ("basic_pay", _("Basic Pay")),
        ("gross_pay", _("Gross Pay")),
    ]

    based_on_choice = [
        ("basic_pay", _("Basic Pay")),
        ("gross_pay", _("Gross Pay")),
        ("taxable_gross_pay", _("Taxable Gross Pay")),
        ("net_pay", _("Net Pay")),
    ]

    exceed_choice = [
        ("ignore", _("Exclude the deduction")),
        ("max_amount", _("Provide max amount")),
    ]

    title = models.CharField(max_length=255, help_text=_("Title of the deduction"))
    one_time_date = models.DateField(
        null=True,
        blank=True,
        help_text=_(
            "The one-time deduction in which the deduction will apply to the payslips \
            if the date between the payslip period"
        ),
    )
    include_active_employees = models.BooleanField(
        default=False,
        verbose_name=_("Include all active employees"),
        help_text=_("Target deduction to all active employees in the company"),
    )
    specific_employees = models.ManyToManyField(
        Employee,
        verbose_name=_("Employees Specific"),
        related_name="deduction_specific",
        help_text=_("Target deduction to the specific employees"),
        blank=True,
    )
    exclude_employees = models.ManyToManyField(
        Employee,
        verbose_name=_("Exclude Employees"),
        related_name="deduction_exclude",
        blank=True,
        help_text=_(
            "To ignore the deduction to the employees when target them by all employees \
            or through condition-based"
        ),
    )

    is_tax = models.BooleanField(
        default=False,
        help_text=_("To specify the deduction is tax or normal deduction"),
    )

    is_pretax = models.BooleanField(
        default=True,
        help_text=_(
            "To find taxable gross, \
            taxable_gross = (basic_pay + taxable_deduction)-pre_tax_deductions "
        ),
    )

    is_condition_based = models.BooleanField(
        default=False,
        help_text=_(
            "This field is used to target deduction \
        to the specific employees when the condition satisfies with the employee's information"
        ),
    )
    # If condition based then must fill field, value, and condition,
    field = models.CharField(
        max_length=255,
        choices=FIELD_CHOICE,
        null=True,
        blank=True,
        help_text=_("The related field of the employees"),
    )
    condition = models.CharField(
        max_length=255, choices=CONDITION_CHOICE, null=True, blank=True
    )
    value = models.CharField(
        max_length=255,
        null=True,
        blank=True,
        help_text=_("The value must be like the data stored in the database"),
    )
    update_compensation = models.CharField(
        null=True,
        blank=True,
        max_length=10,
        choices=[
            (
                "basic_pay",
                _("Basic pay"),
            ),
            ("gross_pay", _("Gross Pay")),
            ("net_pay", _("Net Pay")),
        ],
        help_text=_(
            "Update compensation is used to update \
                   pay-head before any other deduction calculation starts"
        ),
    )
    is_fixed = models.BooleanField(
        default=True,
        help_text=_("To specify, the deduction is fixed or not"),
    )
    # If fixed amount then fill amount
    amount = models.FloatField(
        null=True,
        blank=True,
        validators=[min_zero],
        help_text=_("Fixed amount for this deduction"),
    )
    based_on = models.CharField(
        max_length=255,
        choices=based_on_choice,
        null=True,
        blank=True,
        help_text=_(
            "If the deduction is not fixed then specifies how the deduction provided"
        ),
    )
    rate = models.FloatField(
        null=True,
        blank=True,
        default=0.00,
        validators=[
            rate_validator,
        ],
        verbose_name=_("Employee rate"),
        help_text=_("The percentage of based on"),
    )

    employer_rate = models.FloatField(
        default=0.00,
        validators=[
            rate_validator,
        ],
    )
    has_max_limit = models.BooleanField(
        default=False,
        verbose_name=_("Has max limit for deduction"),
        help_text=_("Limit the deduction"),
    )
    maximum_amount = models.FloatField(
        null=True,
        blank=True,
        validators=[min_zero],
        help_text=_("The maximum amount for the deduction"),
    )

    maximum_unit = models.CharField(
        max_length=20,
        null=True,
        default="month_working_days",
        choices=[
            ("month_working_days", _("For working days on month")),
            # ("monthly_working_days", "For working days on month"),
        ],
        help_text=_("The maximum amount for ?"),
    )
    if_choice = models.CharField(
        max_length=10,
        choices=if_condition_choice,
        default="basic_pay",
        help_text=_("The pay head for the if condition"),
    )
    if_condition = models.CharField(
        max_length=10,
        choices=IF_CONDITION_CHOICE,
        default="gt",
        help_text=_("Apply for those, if the pay-head conditions satisfy"),
    )
    if_amount = models.FloatField(
        default=0.00, help_text=_("The amount of the pay-head")
    )
    company_id = models.ForeignKey(
        Company, null=True, editable=False, on_delete=models.PROTECT
    )
    only_show_under_employee = models.BooleanField(default=False, editable=False)
    objects = HorillaCompanyManager()

    is_installment = models.BooleanField(default=False, editable=False)
    other_conditions = models.ManyToManyField(
        MultipleCondition, blank=True, editable=False
    )

    def installment_payslip(self):
        """
        Method to retrieve the payslip associated with this installment.
        """
        payslip = Payslip.objects.filter(installment_ids=self).first()
        return payslip

    def clean(self):
        super().clean()

        if self.is_tax:
            self.is_pretax = False
        if not self.is_fixed:
            if not self.based_on:
                raise ValidationError(
                    _(
                        "If the 'Is fixed' field is disabled, the 'Based on' field is required."
                    )
                )
        if not self.is_fixed and self.based_on and not self.rate:
            raise ValidationError(
                _(
                    "Employee rate must be specified for deductions that are not fixed amount"
                )
            )

        if self.is_pretax and self.based_on in ["taxable_gross_pay"]:
            raise ValidationError(
                {
                    "based_on": _(
                        " Don't choose taxable gross pay when pretax is enabled."
                    )
                }
            )
        if self.is_pretax and self.based_on in ["net_pay"]:
            raise ValidationError(
                {"based_on": _(" Don't choose net pay when pretax is enabled.")}
            )
        if self.is_tax and self.based_on in ["net_pay"]:
            raise ValidationError(
                {"based_on": _(" Don't choose net pay when the tax is enabled.")}
            )
        if not self.is_fixed:
            self.amount = None
        else:
            self.based_on = None
            self.rate = None
        self.clean_condition_based_on()
        if self.has_max_limit:
            if self.maximum_amount is None:
                raise ValidationError({"maximum_amount": _("This fields required")})

        if self.is_condition_based:
            if not self.field or not self.value or not self.condition:
                raise ValidationError(
                    {
                        "is_condition_based": _(
                            "If condition based, all fields \
                            (field, value, condition) must be filled."
                        )
                    }
                )
        if self.update_compensation is None:
            if self.is_fixed:
                if self.amount is None:
                    raise ValidationError({"amount": _("This field is required")})

    def clean_condition_based_on(self):
        """
        Clean the field, condition, and value attributes when not condition-based.
        """
        if not self.is_condition_based:
            self.field = None
            self.condition = None
            self.value = None

    def __str__(self) -> str:
        return str(self.title)

    def save(self):
        super().save()
        if (
            not self.include_active_employees
            and not self.specific_employees.first()
            and not self.is_condition_based
        ):
            self.include_active_employees = True
            super().save()

class Payslip(HorillaModel):
    """
    Payslip model
    """

    status_choices = [
        ("draft", _("Draft")),
        ("review_ongoing", _("Review Ongoing")),
        ("confirmed", _("Confirmed")),
        ("paid", _("Paid")),
    ]
    group_name = models.CharField(
        max_length=50, null=True, blank=True, verbose_name=_("Batch name")
    )
    reference = models.CharField(max_length=255, unique=False)
    employee_id = models.ForeignKey(
        Employee, on_delete=models.PROTECT, verbose_name=_("Employee")
    )
    start_date = models.DateField()
    end_date = models.DateField()
    pay_head_data = models.JSONField()
    contract_wage = models.FloatField(null=True, default=0)
    basic_pay = models.FloatField(null=True, default=0)
    gross_pay = models.FloatField(null=True, default=0)
    deduction = models.FloatField(null=True, default=0)
    net_pay = models.FloatField(null=True, default=0)
    status = models.CharField(
        max_length=20, null=True, default="draft", choices=status_choices
    )
    sent_to_employee = models.BooleanField(null=True, default=False)
    objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
    installment_ids = models.ManyToManyField(Deduction, editable=False)
    history = HorillaAuditLog(
        related_name="history_set",
        bases=[
            HorillaAuditInfo,
        ],
    )

    def __str__(self) -> str:
        return f"Payslip for {self.employee_id} - Period: {self.start_date} to {self.end_date}"

    def clean(self):
        super().clean()
        today = date.today()
        if self.end_date < self.start_date:
            raise ValidationError(
                {
                    "end_date": _(
                        "The end date must be greater than or equal to the start date"
                    )
                }
            )
        if self.end_date > today:
            raise ValidationError(_("The end date cannot be in the future."))
        if self.start_date > today:
            raise ValidationError(_("The start date cannot be in the future."))

    def save(self, *args, **kwargs):
        if (
            Payslip.objects.filter(
                employee_id=self.employee_id,
                start_date=self.start_date,
                end_date=self.end_date,
            ).count()
            > 1
        ):
            raise ValidationError(_("Employee ,start and end date must be unique"))

        if not isinstance(self.pay_head_data, (QueryDict, dict)):
            raise ValidationError(_("The data must be in dictionary or querydict type"))

        super().save(*args, **kwargs)

    def get_name(self):
        """
        Method is used to get the full name of the owner
        """
        return self.employee_id.get_full_name()

    def get_company(self):
        """
        Method is used to get the full name of the owner
        """
        return getattr(
            getattr(
                getattr(getattr(self, "employee_id", None), "employee_work_info", None),
                "company_id",
                None,
            ),
            "company",
            None,
        )

    def get_payslip_title(self):
        """
        Method to generate the title for a payslip.
        Returns:
            str: The title for the payslip.
        """
        if self.group_name:
            return self.group_name
        return (
            f"Payslip {self.start_date} to {self.end_date}"
            if self.start_date != self.end_date
            else f"Payslip for {self.start_date}"
        )

    def get_days_in_month(self):
        year = self.start_date.year
        month = self.start_date.month
        return calendar.monthrange(year, month)[1]

    class Meta:
        """
        Meta class for additional options
        """

        ordering = [
            "-end_date",
        ]

class LoanAccount(HorillaModel):
    """
    This modal is used to store the loan Account details
    """

    loan_type = [
        ("loan", _("Loan")),
        ("advanced_salary", _("Advanced Salary")),
        ("fine", _("Penalty / Fine")),
    ]
    type = models.CharField(default="loan", choices=loan_type, max_length=15)
    title = models.CharField(max_length=20)
    employee_id = models.ForeignKey(
        Employee, on_delete=models.PROTECT, verbose_name=_("Employee")
    )
    loan_amount = models.FloatField(default=0, verbose_name=_("Amount"))
    provided_date = models.DateField()
    allowance_id = models.ForeignKey(
        Allowance, on_delete=models.SET_NULL, editable=False, null=True
    )
    description = models.TextField(null=True, max_length=255)
    deduction_ids = models.ManyToManyField(Deduction, editable=False)
    is_fixed = models.BooleanField(default=True, editable=False)
    rate = models.FloatField(default=0, editable=False)
    installments = models.IntegerField(verbose_name=_("Total installments"))
    installment_start_date = models.DateField(
        help_text="From the start date deduction will apply"
    )
    apply_on = models.CharField(default="end_of_month", max_length=10, editable=False)
    settled = models.BooleanField(default=False)
    asset_id = models.ForeignKey(
        Asset, on_delete=models.PROTECT, null=True, editable=False
    )
    objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")

    def get_installments(self):
        """
        Method to calculate installment schedule for the loan.

        Returns:
            dict: A dictionary representing the installment schedule with installment dates as keys
            and corresponding installment amounts as values.
        """
        loan_amount = self.loan_amount
        total_installments = self.installments
        installment_amount = loan_amount / total_installments
        installment_start_date = self.installment_start_date

        installment_schedule = {}

        installment_date = installment_start_date
        installment_date_copy = installment_start_date
        installment_schedule = {}
        for _ in range(total_installments):
            installment_schedule[str(installment_date)] = installment_amount
            month = installment_date.month + 1
            year = installment_date.year
            if month > 12:
                month = 1
                year = year + 1
            day = installment_date_copy.day
            total_days_in_month = calendar.monthrange(year, month)[1]
            day = min(day, total_days_in_month)
            installment_date = date(day=day, month=month, year=year)

        return installment_schedule

    def delete(self, *args, **kwargs):
        """
        Method to delete the instance and associated objects.
        """
        self.deduction_ids.all().delete()
        if self.allowance_id is not None:
            self.allowance_id.delete()
        if not Payslip.objects.filter(
            installment_ids__in=list(self.deduction_ids.values_list("id", flat=True))
        ).exists():
            super().delete(*args, **kwargs)
        return

    def installment_ratio(self):
        """
        Method to calculate the ratio of paid installments to total installments in loan account.
        """
        total_installments = self.installments
        installment_paid = Payslip.objects.filter(
            installment_ids__in=self.deduction_ids.all()
        ).count()
        if not installment_paid:
            return 0
        return (installment_paid / total_installments) * 100

@receiver(post_save, sender=LoanAccount)
def create_installments(sender, instance, created, **kwargs):
    """
    Post save metod for loan account
    """
    installments = []
    if created and instance.asset_id is None and instance.type != "fine":
        loan = Allowance()
        loan.amount = instance.loan_amount
        loan.title = instance.title
        loan.include_active_employees = False
        loan.amount = instance.loan_amount
        loan.only_show_under_employee = True
        loan.is_fixed = True
        loan.one_time_date = instance.provided_date
        loan.is_loan = True
        loan.save()
        loan.include_active_employees = False
        loan.specific_employees.add(instance.employee_id)
        loan.save()
        instance.allowance_id = loan
        # Here create the instance...
        super(LoanAccount, instance).save()
    else:
        deductions = instance.deduction_ids.values_list("id", flat=True)
        # Re create deduction only when existing installment not exists in payslip
        if not Payslip.objects.filter(installment_ids__in=deductions).exists():
            Deduction.objects.filter(id__in=deductions).delete()

            # Installment deductions
            for (
                installment_date,
                installment_amount,
            ) in instance.get_installments().items():
                installment = Deduction()
                installment.title = instance.title
                installment.include_active_employees = False
                installment.amount = installment_amount
                installment.is_fixed = True
                installment.one_time_date = installment_date
                installment.only_show_under_employee = True
                installment.is_installment = True
                installment.save()
                installment.include_active_employees = False
                installment.specific_employees.add(instance.employee_id)
                installment.save()
                installments.append(installment)
            instance.deduction_ids.set(installments)

class ReimbursementMultipleAttachment(models.Model):
    """
    ReimbursementMultipleAttachement Model
    """

    attachment = models.FileField(upload_to="payroll/reimbursements")
    objects = models.Manager()

class Reimbursement(HorillaModel):
    """
    Reimbursement Model
    """

    reimbursement_types = [
        ("reimbursement", "Reimbursement"),
        ("leave_encashment", "Leave Encashment"),
        ("bonus_encashment", "Bonus Point Encashment"),
    ]
    status_types = [
        ("requested", "Requested"),
        ("approved", "Approved"),
        ("rejected", "Rejected"),
    ]
    title = models.CharField(max_length=50)
    type = models.CharField(
        choices=reimbursement_types, max_length=16, default="reimbursement"
    )
    employee_id = models.ForeignKey(
        Employee, on_delete=models.PROTECT, verbose_name="Employee"
    )
    allowance_on = models.DateField()
    attachment = models.FileField(upload_to="payroll/reimbursements", null=True)
    other_attachments = models.ManyToManyField(
        ReimbursementMultipleAttachment, blank=True, editable=False
    )
    leave_type_id = models.ForeignKey(
        LeaveType,
        on_delete=models.PROTECT,
        blank=True,
        null=True,
        verbose_name="Leave type",
    )
    ad_to_encash = models.FloatField(
        default=0, help_text="Available Days to encash", verbose_name="Available days"
    )
    cfd_to_encash = models.FloatField(
        default=0,
        help_text="Carry Forward Days to encash",
        verbose_name="Carry forward days",
    )
    bonus_to_encash = models.IntegerField(
        default=0,
        help_text="Bonus points to encash",
        verbose_name="Bonus points",
    )
    amount = models.FloatField(default=0)
    status = models.CharField(
        max_length=10, choices=status_types, default="requested", editable=False
    )
    approved_by = models.ForeignKey(
        Employee,
        on_delete=models.SET_NULL,
        null=True,
        related_name="approved_by",
        editable=False,
    )
    description = models.TextField(null=True, max_length=255)
    allowance_id = models.ForeignKey(
        Allowance, on_delete=models.SET_NULL, null=True, editable=False
    )
    objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")

    class Meta:
        ordering = ["-id"]

    def save(self, *args, **kwargs) -> None:
        request = getattr(thread_local_middleware._thread_locals, "request", None)
        amount_for_leave = (
            EncashmentGeneralSettings.objects.first().leave_amount
            if EncashmentGeneralSettings.objects.first()
            else 1
        )

        # Setting the created use if the used dont have the permission
        has_perm = request.user.has_perm("payroll.add_reimbursement")
        if not has_perm:
            self.employee_id = request.user.employee_get
        if self.type == "reimbursement" and self.attachment is None:
            raise ValidationError({"attachment": "This field is required"})
        if self.type == "leave_encashment" and self.leave_type_id is None:
            raise ValidationError({"leave_type_id": "This field is required"})
        if self.type == "leave_encashment":
            if self.status == "requested":
                self.amount = (
                    self.cfd_to_encash + self.ad_to_encash
                ) * amount_for_leave
            self.cfd_to_encash = max((round(self.cfd_to_encash * 2) / 2), 0)
            self.ad_to_encash = max((round(self.ad_to_encash * 2) / 2), 0)
            assigned_leave = self.leave_type_id.employee_available_leave.filter(
                employee_id=self.employee_id
            ).first()
        if self.status != "approved" or self.allowance_id is None:
            super().save(*args, **kwargs)
            if self.status == "approved" and self.allowance_id is None:
                if self.type == "reimbursement":
                    proceed = True
                elif self.type == "bonus_encashment":
                    proceed = False
                    bonus_points = BonusPoint.objects.get(employee_id=self.employee_id)
                    if bonus_points.points >= self.bonus_to_encash:
                        proceed = True
                        bonus_points.points -= self.bonus_to_encash
                        bonus_points.reason = "bonus points has been redeemed."
                        bonus_points.save()
                    else:
                        request = getattr(
                            thread_local_middleware._thread_locals, "request", None
                        )
                        if request:
                            messages.info(
                                request,
                                "The employee don't have that much bonus points to encash.",
                            )
                else:
                    proceed = False
                    if assigned_leave:
                        available_days = assigned_leave.available_days
                        carryforward_days = assigned_leave.carryforward_days
                        if (
                            available_days >= self.ad_to_encash
                            and carryforward_days >= self.cfd_to_encash
                        ):
                            proceed = True
                            assigned_leave.available_days = (
                                available_days - self.ad_to_encash
                            )
                            assigned_leave.carryforward_days = (
                                carryforward_days - self.cfd_to_encash
                            )
                            assigned_leave.save()
                        else:
                            request = getattr(
                                thread_local_middleware._thread_locals, "request", None
                            )
                            if request:
                                messages.info(
                                    request,
                                    _(
                                        "The employee don't have that much leaves \
                                        to encash in CFD / Available days"
                                    ),
                                )

                if proceed:
                    reimbursement = Allowance()
                    reimbursement.one_time_date = self.allowance_on
                    reimbursement.title = self.title
                    reimbursement.only_show_under_employee = True
                    reimbursement.include_active_employees = False
                    reimbursement.amount = self.amount
                    reimbursement.save()
                    reimbursement.include_active_employees = False
                    reimbursement.specific_employees.add(self.employee_id)
                    reimbursement.save()
                    self.allowance_id = reimbursement
                    if request:
                        self.approved_by = request.user.employee_get
                else:
                    self.status = "requested"
                super().save(*args, **kwargs)
            elif self.status == "rejected" and self.allowance_id is not None:
                cfd_days = self.cfd_to_encash
                available_days = self.ad_to_encash
                if self.type == "leave encashment":
                    if assigned_leave:
                        assigned_leave.available_days = (
                            assigned_leave.available_days + available_days
                        )
                        assigned_leave.carryforward_days = (
                            assigned_leave.carryforward_days + cfd_days
                        )
                        assigned_leave.save()
                    self.allowance_id.delete()

    def delete(self, *args, **kwargs):
        request = getattr(thread_local_middleware._thread_locals, "request", None)
        if self.status == "approved":
            message = messages.info(
                request,
                _(
                    f"{self.title} is in approved state,\
                    it cannot be deleted"
                ),
            )
        else:
            if self.allowance_id:
                self.allowance_id.delete()
                super().delete(*args, **kwargs)
                message = messages.success(request, "Reimbursement deleted")

        return message

    def __str__(self):
        return f"{self.title}"

# changing status canceled to reject for existing reimbursement
try:
    if Reimbursement.objects.filter(status="canceled").exists():
        Reimbursement.objects.filter(status="canceled").update(status="rejected")
except:
    pass

class ReimbursementFile(models.Model):
    file = models.FileField(upload_to="payroll/request_files")
    objects = models.Manager()

class ReimbursementrequestComment(HorillaModel):
    """
    ReimbursementRequestComment Model
    """

    request_id = models.ForeignKey(Reimbursement, on_delete=models.CASCADE)
    employee_id = models.ForeignKey(Employee, on_delete=models.CASCADE)
    comment = models.TextField(null=True, verbose_name=_("Comment"), max_length=255)
    files = models.ManyToManyField(ReimbursementFile, blank=True)
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_("Created At"),
        null=True,
    )

    def __str__(self) -> str:
        return f"{self.comment}"

class PayrollGeneralSetting(models.Model):
    """
    PayrollGeneralSetting
    """

    notice_period = models.IntegerField(
        help_text="Notice period in days",
        validators=[min_zero],
        default=30,
    )
    company_id = models.ForeignKey(Company, on_delete=models.CASCADE, null=True)

class EncashmentGeneralSettings(models.Model):
    """
    BonusPointGeneralSettings model
    """

    bonus_amount = models.IntegerField(default=1)
    leave_amount = models.IntegerField(blank=True, null=True, verbose_name="Amount")
    objects = models.Manager()
horilla-opensource commented 2 months ago

Hi @rbale0831 , Please share the initial migration file for the payroll app. Sorry for the confusion.

rbale0831 commented 2 months ago

C:\Horilla\horilla\payroll\migrations__pycache__\0001_initial.cpython-310.pyc

https://drive.google.com/drive/folders/1FzByqui5Ov4Uw8Er7VCZmXt8BEjWKtU_?usp=sharing

i have uploaded the payroll folder in drive

horilla-opensource commented 2 months ago

Hi @rbale0831 , Can you please replace all the field definitions with max_length=255 to max_length=191 in the models.py file (Payroll > models > models.py )

For example:

description = models.TextField(
        blank=True,
        verbose_name=_("Description"),
        max_length=255,
    )

TO

description = models.TextField(
        blank=True,
        verbose_name=_("Description"),
        max_length=191,
    )

There will be around 23 definitions that you'll have to change. Please run the makemigrations and migrate command and let us know if you face any issues.

With Regards, Team Horilla

horilla-opensource commented 2 months ago

Hi @rbale0831 , Were you able to proceed with the suggestion we have provided ?

With Regards, Team Horilla

rbale0831 commented 1 month ago

Hi @horilla-opensource,

I was not able to proceed with the provided suggestion. Is the issue with the MySQL data fixed in the current version of Horilla? If not, can you please let me know when this issue with the MySQL database will be fixed?

with Regards, Rohit

horilla-opensource commented 1 week ago

Hi @rbale0831 , Were you able to workaround with it?

With Regards, Team Horilla