diff --git a/reset_apps.ts b/reset_apps.ts index f897c21..6eb6948 100644 --- a/reset_apps.ts +++ b/reset_apps.ts @@ -43,7 +43,7 @@ async function reset() { await db.ApplicationProgress.destroy({ where: { applicationId: app.id, - stageName: ['LOI Approval', 'Security Details', 'LOI Issue', 'Dealer Code Generation', 'Architecture Team Assigned', 'Statutory GST'] + stageName: ['LOI Approval', 'Security Deposit', 'LOI Issue', 'Dealer Code Generation', 'Architecture Team Assigned', 'Statutory GST'] } }); diff --git a/scripts/sql/application_security_deposit_status_rename.sql b/scripts/sql/application_security_deposit_status_rename.sql new file mode 100644 index 0000000..02ccbb2 --- /dev/null +++ b/scripts/sql/application_security_deposit_status_rename.sql @@ -0,0 +1,18 @@ +-- Rename overallStatus value Security Details -> Security Deposit (canonical label from APPLICATION_STATUS.SECURITY_DETAILS). +-- Run once per environment AFTER deploying code that uses 'Security Deposit'. +-- +-- 1) Discover enum type name for applications.overallStatus: +-- SELECT c.column_name, c.udt_name +-- FROM information_schema.columns c +-- WHERE c.table_schema = 'public' AND c.table_name = 'applications' AND c.column_name = 'overallStatus'; +-- +-- 2) Add new enum value (PostgreSQL 9.1+). Replace type name if yours differs. +-- ALTER TYPE "enum_applications_overallStatus" ADD VALUE IF NOT EXISTS 'Security Deposit'; +-- +-- 3) Backfill rows (camelCase column is typical for this Sequelize project). +-- UPDATE applications SET "overallStatus" = 'Security Deposit' WHERE "overallStatus" = 'Security Details'; +-- +-- 4) Backfill ApplicationProgress pipeline stage label (see ONBOARDING_STAGES in progress.ts). +-- UPDATE application_progress SET "stageName" = 'Security Deposit' WHERE "stageName" = 'Security Details'; + +-- Minimal safe block: only step 3+4 if you use VARCHAR-like enums; for native ENUM you must run step 2 first (cannot be in same transaction as use of new value on older PG — run ADD VALUE, COMMIT, then UPDATE). diff --git a/src/common/config/constants.ts b/src/common/config/constants.ts index 3998184..82bb690 100644 --- a/src/common/config/constants.ts +++ b/src/common/config/constants.ts @@ -85,7 +85,7 @@ export const APPLICATION_STATUS = { LEVEL_3_PENDING: 'Level 3 Interview Pending', LEVEL_3_APPROVED: 'Level 3 Approved', FDD_VERIFICATION: 'FDD Verification', - SECURITY_DETAILS: 'Security Details', + SECURITY_DETAILS: 'Security Deposit', PAYMENT_PENDING: 'Payment Pending', LOI_IN_PROGRESS: 'LOI In Progress', LOI_ISSUED: 'LOI Issued', @@ -142,6 +142,8 @@ export const OVERALL_STATUS_TO_DB_CURRENT_STAGE: Record< [APPLICATION_STATUS.LEVEL_3_APPROVED]: APPLICATION_STAGES.LEVEL_3_APPROVED, [APPLICATION_STATUS.FDD_VERIFICATION]: APPLICATION_STAGES.FDD, [APPLICATION_STATUS.SECURITY_DETAILS]: APPLICATION_STAGES.LOI, + /** Legacy `overallStatus` before rename; remove after DB migrated */ + 'Security Details': APPLICATION_STAGES.LOI, [APPLICATION_STATUS.PAYMENT_PENDING]: APPLICATION_STAGES.LOI, [APPLICATION_STATUS.LOI_IN_PROGRESS]: APPLICATION_STAGES.LOI, [APPLICATION_STATUS.LOI_ISSUED]: APPLICATION_STAGES.LOI, diff --git a/src/common/utils/progress.ts b/src/common/utils/progress.ts index 1f1db2d..93f36ac 100644 --- a/src/common/utils/progress.ts +++ b/src/common/utils/progress.ts @@ -10,7 +10,7 @@ export const ONBOARDING_STAGES = [ { name: '3rd Level Interview', order: 6 }, { name: 'FDD', order: 7 }, { name: 'LOI Approval', order: 8 }, - { name: 'Security Details', order: 9 }, + { name: 'Security Deposit', order: 9 }, { name: 'LOI Issue', order: 10 }, { name: 'Dealer Code Generation', order: 11 }, { name: 'Architecture Work', order: 12 }, @@ -107,8 +107,10 @@ export const PIPELINE_STAGE_LABEL_BY_OVERALL_STATUS: Record = { 'Level 3 Approved': '3rd Level Interview', 'FDD Verification': 'FDD', 'LOI In Progress': 'LOI Approval', - 'Security Details': 'Security Details', - 'Payment Pending': 'Security Details', + /** @deprecated DB rows may still use pre-rename label until migrated */ + 'Security Details': 'Security Deposit', + 'Security Deposit': 'Security Deposit', + 'Payment Pending': 'Security Deposit', 'LOI Issued': 'LOI Issue', 'Statutory LOI Ack': 'LOI Issue', 'Dealer Code Generation': 'Dealer Code Generation', diff --git a/src/modules/audit/audit.controller.ts b/src/modules/audit/audit.controller.ts index a79ea88..574e977 100644 --- a/src/modules/audit/audit.controller.ts +++ b/src/modules/audit/audit.controller.ts @@ -51,7 +51,7 @@ const ACTION_DESCRIPTIONS: Record = { DEALER_UPDATED: 'Dealer profile updated', DEALER_CODE_GENERATED: 'Dealer code generated', PAYMENT_UPDATED: 'Payment record updated', - SECURITY_DEPOSIT_UPDATED: 'Security deposit updated', + SECURITY_DEPOSIT_UPDATED: 'Security Deposit updated', FNF_UPDATED: 'F&F settlement updated', CLEARANCE_UPDATED: 'Departmental clearance response recorded', STAKEHOLDER_CLEARANCE_UPDATED: 'F&F stakeholder clearance synced', diff --git a/src/modules/loa/loa.controller.ts b/src/modules/loa/loa.controller.ts index 342156e..405561c 100644 --- a/src/modules/loa/loa.controller.ts +++ b/src/modules/loa/loa.controller.ts @@ -451,13 +451,15 @@ export const updateSecurityDeposit = async (req: AuthRequest, res: Response) => if ((depositType === 'SECURITY_DEPOSIT' || !depositType) && status === 'Verified') { const os = application.overallStatus; const inInitialSdCorridor = - os === APPLICATION_STATUS.PAYMENT_PENDING || os === APPLICATION_STATUS.SECURITY_DETAILS; + os === APPLICATION_STATUS.PAYMENT_PENDING || + os === APPLICATION_STATUS.SECURITY_DETAILS || + os === 'Security Details'; if (inInitialSdCorridor) { console.log( - `[DEBUG] SECURITY_DEPOSIT verified (overallStatus=${os}). Aligning to Security Details for admin before LOI Issued.`, + `[DEBUG] SECURITY_DEPOSIT verified (overallStatus=${os}). Aligning to Security Deposit for admin before LOI Issued.`, ); await WorkflowService.transitionApplication(application, APPLICATION_STATUS.SECURITY_DETAILS, req.user?.id || null, { - reason: 'Security deposit verified by Finance. Awaiting admin approval to proceed to LOI issuance.', + reason: 'Security Deposit verified by Finance. Awaiting admin approval to proceed to LOI issuance.', stage: APPLICATION_STAGES.LOI, progressPercentage: 78 }); @@ -492,7 +494,7 @@ export const updateSecurityDeposit = async (req: AuthRequest, res: Response) => res.json({ success: true, message: 'Security Deposit updated', data: updatedDeposit }); } catch (error) { console.error('Update Security Deposit error:', error); - res.status(500).json({ success: false, message: 'Error updating security deposit' }); + res.status(500).json({ success: false, message: 'Error updating Security Deposit' }); } }; @@ -517,6 +519,6 @@ export const getSecurityDeposit = async (req: Request, res: Response) => { res.json({ success: true, data: deposits }); } catch (error) { console.error('Fetch Security Deposit error:', error); - res.status(500).json({ success: false, message: 'Error fetching security deposit' }); + res.status(500).json({ success: false, message: 'Error fetching Security Deposit' }); } }; diff --git a/src/modules/loi/loi.controller.ts b/src/modules/loi/loi.controller.ts index ec1e35e..b83c837 100644 --- a/src/modules/loi/loi.controller.ts +++ b/src/modules/loi/loi.controller.ts @@ -111,8 +111,8 @@ export const acknowledgeRequest = async (req: AuthRequest, res: Response) => { const phone = (applicantUser as any)?.mobileNumber || application.phone || ''; await NotificationService.notify(applicantUser?.id ?? null, application.email, { - title: `Security deposit — ${application.applicationId}`, - message: `Please remit the security deposit for ${application.applicationId} as per your LOI.`, + title: `Security Deposit — ${application.applicationId}`, + message: `Please remit the Security Deposit for ${application.applicationId} as per your LOI.`, channels: phone ? ['email', 'whatsapp'] : ['email'], templateCode: 'SECURITY_DEPOSIT_REQUEST', placeholders: { @@ -125,7 +125,7 @@ export const acknowledgeRequest = async (req: AuthRequest, res: Response) => { ctaLabel: 'Pay or upload proof', phone: String(phone || '') } - }).catch((e: any) => console.error('[LOI] Security deposit email failed:', e)); + }).catch((e: any) => console.error('[LOI] Security Deposit email failed:', e)); } res.json({ success: true, message: 'LOI Acknowledged by applicant' }); diff --git a/src/scripts/seed-master-emails.ts b/src/scripts/seed-master-emails.ts index 8fb1339..515e324 100644 --- a/src/scripts/seed-master-emails.ts +++ b/src/scripts/seed-master-emails.ts @@ -145,7 +145,7 @@ const seedTemplates = async () => { }, { templateCode: 'ONBOARDING_PAYMENT_VERIFIED', - description: 'Notification when security deposit or initial payment is verified', + description: 'Notification when Security Deposit or initial payment is verified', subject: 'Payment Verified: {{applicationId}}', fileName: 'onboarding_payment_verified.html', placeholders: ['applicationId', 'dealerName', 'paymentType', 'amount', 'link'] @@ -355,7 +355,7 @@ const seedTemplates = async () => { }, { templateCode: 'SECURITY_DEPOSIT_REQUEST', - description: 'After LOI acknowledgement: security deposit payment instructions', + description: 'After LOI acknowledgement: Security Deposit payment instructions', subject: 'Security Deposit Payment Required — {{applicationId}}', fileName: 'security_deposit_request.html', placeholders: ['applicantName', 'applicationId', 'amount', 'dueDate', 'bankDetails', 'link', 'ctaLabel'] diff --git a/src/services/WorkflowIntegrityService.ts b/src/services/WorkflowIntegrityService.ts index 1298034..a564a75 100644 --- a/src/services/WorkflowIntegrityService.ts +++ b/src/services/WorkflowIntegrityService.ts @@ -26,7 +26,14 @@ export class WorkflowIntegrityService { } // LOI STAGE INTEGRITY - if ([APPLICATION_STATUS.LOI_IN_PROGRESS, APPLICATION_STATUS.PAYMENT_PENDING, APPLICATION_STATUS.SECURITY_DETAILS].includes(application.overallStatus)) { + // Include legacy DB label "Security Details" until data migration completes. + const loiPreIssuedStatuses = [ + APPLICATION_STATUS.LOI_IN_PROGRESS, + APPLICATION_STATUS.PAYMENT_PENDING, + APPLICATION_STATUS.SECURITY_DETAILS, + 'Security Details' + ]; + if (loiPreIssuedStatuses.includes(application.overallStatus)) { await this.syncLoiIntegrity(application); } @@ -114,7 +121,7 @@ export class WorkflowIntegrityService { }); if (policyMet && deposit) { - console.log(`[WorkflowIntegrityService] Policy met and payment verified for LOI on ${application.applicationId}. Aligning to Security Details for admin approval before LOI Issued.`); + console.log(`[WorkflowIntegrityService] Policy met and payment verified for LOI on ${application.applicationId}. Aligning to Security Deposit for admin approval before LOI Issued.`); // Ensure LoiRequest is also updated const request = await db.LoiRequest.findOne({ where: { applicationId: application.id } }); @@ -123,7 +130,7 @@ export class WorkflowIntegrityService { } await WorkflowService.transitionApplication(application, APPLICATION_STATUS.SECURITY_DETAILS, null, { - reason: 'Integrity sync: LOI policy and deposit verified — use Security Details admin approval to reach LOI Issued.', + reason: 'Integrity sync: LOI policy and deposit verified — use Security Deposit admin approval to reach LOI Issued.', progressPercentage: 78 }); } diff --git a/trigger-workflow.js b/trigger-workflow.js index cb160be..8ce1e15 100644 --- a/trigger-workflow.js +++ b/trigger-workflow.js @@ -426,8 +426,8 @@ async function triggerWorkflow() { await ensureMandatoryCodeGenFields(applicationUUID, adminToken); await delay(300); - if (statusBeforeCodeGen === 'Security Details') { - log(9, 'Status is Security Details; re-verifying Security Deposit to move to LOI Issued...'); + if (statusBeforeCodeGen === 'Security Deposit' || statusBeforeCodeGen === 'Security Details') { + log(9, 'Status is Security Deposit (or legacy Security Details); re-verifying Security Deposit to move to LOI Issued...'); await apiRequest('/loa/security-deposit', 'POST', { applicationId: applicationUUID, amount: 500000, @@ -440,13 +440,13 @@ async function triggerWorkflow() { log(9, `Status after re-verify: ${statusBeforeCodeGen}`); } - // Current backend flow keeps app at "Security Details" until explicit admin transition. - if (statusBeforeCodeGen === 'Security Details') { - log(9, 'Applying admin transition from Security Details -> LOI Issued...'); + // Current backend flow keeps app at Security Deposit until explicit admin transition. + if (statusBeforeCodeGen === 'Security Deposit' || statusBeforeCodeGen === 'Security Details') { + log(9, 'Applying admin transition from Security Deposit -> LOI Issued...'); await apiRequest(`/onboarding/applications/${applicationUUID}/status`, 'PUT', { status: 'LOI Issued', stage: 'LOI', - reason: 'E2E script alignment: unlock dealer code generation after Security Details checks.' + reason: 'E2E script alignment: unlock dealer code generation after Security Deposit checks.' }, adminToken); await delay(); statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);