using System.Globalization; namespace TMSDAL.Query.TrainingEnrollment { /// /// Query bank for TTRAININGENROLLMENT. /// /// Required indexes: /// IX_TTRAININGENROLLMENT_INSTANCEID_TENANTID /// IX_TTRAININGENROLLMENT_EMPLOYEEID_TENANTID /// IX_TTRAININGENROLLMENT_STATUS_TENANTID /// public static class TrainingEnrollmentQB { // ════════════════════════════════════════════════════════════════════ // READ — Single Record // ════════════════════════════════════════════════════════════════════ /// Fetch full enrollment record by primary key. public const string GET_ENROLLMENT = @" SELECT te.ENROLLMENTID AS EnrollmentId, te.ENROLLMENTCODE AS EnrollmentCode, te.ENROLLMENTNAME AS EnrollmentName, te.INSTANCEID AS InstanceId, ti.INSTANCECODE AS InstanceCode, tp.PROGRAMMETITLE AS ProgrammeTitle, te.EMPLOYEEID AS EmployeeId, e.EMPLOYEENAME AS EmployeeName, te.NOMINATIONSOURCE AS NominationSource, te.NOMINATEDBYID AS NominatedById, nb.EMPLOYEENAME AS NominatedByName, -- FIX: join to get name te.NOMINATEDON AS NominatedOn, -- FIX: was missing te.MANAGERAPPROVALID AS ManagerApprovalId, te.MANAGERAPPROVEDON AS ManagerApprovedOn, te.HRAPPROVALID AS HRApprovalId, te.ENROLLMENTSTATUS AS EnrollmentStatus, te.WAITLISTPOSITION AS WaitlistPosition, te.PREASSESSMENTDONE AS PreAssessmentDone, -- FIX: was missing te.PREASSESSMENTSCORE AS PreAssessmentScore, -- FIX: was missing te.REMARKS AS Remarks, -- FIX: was missing te.WITHDRAWALREASON AS WithdrawalReason, te.WITHDRAWNON AS WithdrawnOn, te.TENANTID AS TenantId, te.CREATEDBYID AS CreatedById, te.CREATEDON AS CreatedOn, te.MODIFIEDBYID AS ModifiedById, te.MODIFIEDON AS ModifiedOn FROM DBO.TTRAININGENROLLMENT te INNER JOIN DBO.TTRAININGINSTANCE ti ON ti.INSTANCEID = te.INSTANCEID AND ti.TENANTID = te.TENANTID INNER JOIN DBO.MTRAININGPROGRAMME tp ON tp.PROGRAMMEID = ti.PROGRAMMEID AND tp.TENANTID = te.TENANTID INNER JOIN DBO.MEMPLOYEE e ON e.EMPLOYEEID = te.EMPLOYEEID -- FIX: LEFT JOIN for NominatedBy — may be NULL when system-nominated LEFT JOIN DBO.MEMPLOYEE nb ON nb.EMPLOYEEID = te.NOMINATEDBYID WHERE te.ENROLLMENTID = @EnrollmentId AND te.TENANTID = @TenantId;"; // ──────────────────────────────────────────────────────────────────── /// /// NEW: Duplicate-enrollment guard — fetches ACTIVE enrollment only. /// Matches the filtered unique index: excludes Withdrawn(7) and /// all Rejected variants (8, 9, 10) so re-enrollment is allowed /// after those terminal states. /// public const string GET_ENROLLMENT_BY_INSTANCE_EMPLOYEE = @" SELECT TOP 1 te.ENROLLMENTID AS EnrollmentId, te.ENROLLMENTCODE AS EnrollmentCode, te.INSTANCEID AS InstanceId, te.EMPLOYEEID AS EmployeeId, te.ENROLLMENTSTATUS AS EnrollmentStatus FROM DBO.TTRAININGENROLLMENT te WHERE te.INSTANCEID = @InstanceId AND te.EMPLOYEEID = @EmployeeId AND te.TENANTID = @TenantId AND te.ENROLLMENTSTATUS NOT IN (7, 8, 9, 10); -- Excludes: 7=Withdrawn 8=Rejected(legacy) 9=ManagerRejected 10=HRRejected"; // ════════════════════════════════════════════════════════════════════ // READ — Lists // ════════════════════════════════════════════════════════════════════ /// All active enrollments for a training instance. public const string GET_ENROLLMENTS_BY_INSTANCE = @" SELECT te.ENROLLMENTID AS EnrollmentId, te.ENROLLMENTCODE AS EnrollmentCode, te.ENROLLMENTNAME AS EnrollmentName, te.INSTANCEID AS InstanceId, ti.INSTANCECODE AS InstanceCode, tp.PROGRAMMETITLE AS ProgrammeTitle, te.EMPLOYEEID AS EmployeeId, e.EMPLOYEENAME AS EmployeeName, te.NOMINATIONSOURCE AS NominationSource, te.ENROLLMENTSTATUS AS EnrollmentStatus, te.WAITLISTPOSITION AS WaitlistPosition, te.MANAGERAPPROVEDON AS ManagerApprovedOn, te.CREATEDON AS CreatedOn FROM DBO.TTRAININGENROLLMENT te INNER JOIN DBO.TTRAININGINSTANCE ti ON ti.INSTANCEID = te.INSTANCEID AND ti.TENANTID = te.TENANTID INNER JOIN DBO.MTRAININGPROGRAMME tp ON tp.PROGRAMMEID = ti.PROGRAMMEID AND tp.TENANTID = te.TENANTID INNER JOIN DBO.MEMPLOYEE e ON e.EMPLOYEEID = te.EMPLOYEEID WHERE te.INSTANCEID = @InstanceId AND te.TENANTID = @TenantId ORDER BY te.WAITLISTPOSITION, te.CREATEDON;"; /// All enrollments for an employee, newest first. public const string GET_ENROLLMENTS_BY_EMPLOYEE = @" SELECT te.ENROLLMENTID AS EnrollmentId, te.ENROLLMENTCODE AS EnrollmentCode, te.ENROLLMENTNAME AS EnrollmentName, te.INSTANCEID AS InstanceId, ti.INSTANCECODE AS InstanceCode, tp.PROGRAMMETITLE AS ProgrammeTitle, te.EMPLOYEEID AS EmployeeId, e.EMPLOYEENAME AS EmployeeName, te.NOMINATIONSOURCE AS NominationSource, te.ENROLLMENTSTATUS AS EnrollmentStatus, te.WAITLISTPOSITION AS WaitlistPosition, te.MANAGERAPPROVEDON AS ManagerApprovedOn, te.CREATEDON AS CreatedOn FROM DBO.TTRAININGENROLLMENT te INNER JOIN DBO.TTRAININGINSTANCE ti ON ti.INSTANCEID = te.INSTANCEID AND ti.TENANTID = te.TENANTID INNER JOIN DBO.MTRAININGPROGRAMME tp ON tp.PROGRAMMEID = ti.PROGRAMMEID AND tp.TENANTID = te.TENANTID INNER JOIN DBO.MEMPLOYEE e ON e.EMPLOYEEID = te.EMPLOYEEID WHERE te.EMPLOYEEID = @EmployeeId AND te.TENANTID = @TenantId ORDER BY te.CREATEDON DESC;"; /// Full enrollment list for the tenant. public const string GET_ENROLLMENT_LIST = @" SELECT te.ENROLLMENTID AS EnrollmentId, te.ENROLLMENTCODE AS EnrollmentCode, te.ENROLLMENTNAME AS EnrollmentName, te.INSTANCEID AS InstanceId, ti.INSTANCECODE AS InstanceCode, tp.PROGRAMMETITLE AS ProgrammeTitle, te.EMPLOYEEID AS EmployeeId, e.EMPLOYEENAME AS EmployeeName, te.NOMINATIONSOURCE AS NominationSource, te.ENROLLMENTSTATUS AS EnrollmentStatus, te.WAITLISTPOSITION AS WaitlistPosition, te.MANAGERAPPROVEDON AS ManagerApprovedOn, te.CREATEDON AS CreatedOn FROM DBO.TTRAININGENROLLMENT te INNER JOIN DBO.TTRAININGINSTANCE ti ON ti.INSTANCEID = te.INSTANCEID AND ti.TENANTID = te.TENANTID INNER JOIN DBO.MTRAININGPROGRAMME tp ON tp.PROGRAMMEID = ti.PROGRAMMEID AND tp.TENANTID = te.TENANTID INNER JOIN DBO.MEMPLOYEE e ON e.EMPLOYEEID = te.EMPLOYEEID WHERE te.TENANTID = @TenantId ORDER BY te.CREATEDON DESC;"; // ════════════════════════════════════════════════════════════════════ // READ — Waitlist / Picklist // ════════════════════════════════════════════════════════════════════ /// /// Returns MAX(WaitlistPosition) + 1 for the given instance. /// Returns 1 when no waitlisted rows exist (ISNULL handles the NULL). /// public const string GET_NEXT_WAITLIST_POSITION = @" SELECT ISNULL(MAX(WAITLISTPOSITION), 0) + 1 FROM DBO.TTRAININGENROLLMENT WHERE INSTANCEID = @InstanceId AND ENROLLMENTSTATUS = @WaitlistedStatus AND TENANTID = @TenantId;"; /// Dropdown / picklist — minimal fields with meaningful labels. public const string GET_SELECTLIST_TRAINING_ENROLLMENT = @" SELECT te.ENROLLMENTID AS EnrollmentId, te.ENROLLMENTCODE AS EnrollmentCode, te.ENROLLMENTNAME AS EnrollmentName, te.EMPLOYEEID AS EmployeeId, ti.INSTANCECODE AS InstanceCode, tp.PROGRAMMETITLE AS ProgrammeTitle FROM DBO.TTRAININGENROLLMENT te INNER JOIN DBO.TTRAININGINSTANCE ti ON ti.INSTANCEID = te.INSTANCEID AND ti.TENANTID = te.TENANTID INNER JOIN DBO.MTRAININGPROGRAMME tp ON tp.PROGRAMMEID = ti.PROGRAMMEID AND tp.TENANTID = te.TENANTID WHERE te.TENANTID = @TenantId {DYNAMIC_WHERE}"; // ════════════════════════════════════════════════════════════════════ // WRITE // ════════════════════════════════════════════════════════════════════ /// /// Insert a new enrollment record. /// FIX: NOMINATEDON now uses @NominatedOn (not @CreatedOn). /// FIX: WAITLISTPOSITION uses NULL for non-waitlisted (not 0). /// public const string SAVE_ENROLLMENT = @" INSERT INTO DBO.TTRAININGENROLLMENT ( ENROLLMENTID, ENROLLMENTCODE, ENROLLMENTNAME, INSTANCEID, EMPLOYEEID, NOMINATIONSOURCE, NOMINATEDBYID, NOMINATEDON, ENROLLMENTSTATUS, WAITLISTPOSITION, TENANTID, CREATEDBYID, CREATEDON, MODIFIEDBYID, MODIFIEDON ) VALUES ( @EnrollmentId, @EnrollmentCode, @EnrollmentName, @InstanceId, @EmployeeId, @NominationSource, @NominatedById, @NominatedOn, -- FIX: was @CreatedOn — wrong column re-used @EnrollmentStatus, @WaitlistPosition, -- NULL when not waitlisted (BLL sets null, not 0) @TenantId, @CreatedById, @CreatedOn, @ModifiedById, @ModifiedOn );"; /// /// Manager approval / rejection. /// FIX: Writes to MANAGERREMARKS (tier-specific) not shared REMARKS column. /// public const string UPDATE_MANAGER_APPROVAL = @" UPDATE DBO.TTRAININGENROLLMENT SET ENROLLMENTSTATUS = @EnrollmentStatus, MANAGERAPPROVALID = @ManagerApprovalId, MANAGERAPPROVEDON = @ManagerApprovedOn, MANAGERREMARKS = @ManagerRemarks, -- FIX: tier-specific column MODIFIEDBYID = @ModifiedById, MODIFIEDON = @ModifiedOn WHERE ENROLLMENTID = @EnrollmentId AND TENANTID = @TenantId;"; /// /// HR approval / rejection. /// FIX: HRAPPROVEDON replaces HRPROCESSEDON (renamed column). /// FIX: Writes to HRREMARKS (tier-specific) not shared REMARKS column. /// public const string UPDATE_HR_APPROVAL = @" UPDATE DBO.TTRAININGENROLLMENT SET ENROLLMENTSTATUS = @EnrollmentStatus, HRAPPROVALID = @HRApprovalId, HRAPPROVEDON = @HRApprovedOn, -- FIX: was HRPROCESSEDON HRREMARKS = @HRRemarks, -- FIX: tier-specific column MODIFIEDBYID = @ModifiedById, MODIFIEDON = @ModifiedOn WHERE ENROLLMENTID = @EnrollmentId AND TENANTID = @TenantId;"; /// Withdraw an enrollment — records reason and timestamp. public const string WITHDRAW_ENROLLMENT = @" UPDATE DBO.TTRAININGENROLLMENT SET ENROLLMENTSTATUS = @EnrollmentStatus, WITHDRAWALREASON = @WithdrawalReason, WITHDRAWNON = @WithdrawnOn, MODIFIEDBYID = @ModifiedById, MODIFIEDON = @ModifiedOn WHERE ENROLLMENTID = @EnrollmentId AND TENANTID = @TenantId;"; /// /// Soft-delete: sets STATUS = 0. /// FIX: Replaced hard DELETE with soft-delete — enrollment history must be preserved. /// public const string DELETE_ENROLLMENT = @" UPDATE DBO.TTRAININGENROLLMENT SET STATUS = 0, MODIFIEDBYID = @ModifiedById, MODIFIEDON = @ModifiedOn WHERE ENROLLMENTID = @EnrollmentId AND TENANTID = @TenantId;"; } }