bugs were covered
This commit is contained in:
parent
e99a28b7f7
commit
f5022b613d
@ -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']
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
18
scripts/sql/application_security_deposit_status_rename.sql
Normal file
18
scripts/sql/application_security_deposit_status_rename.sql
Normal file
@ -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).
|
||||
@ -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,
|
||||
|
||||
@ -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<string, string> = {
|
||||
'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',
|
||||
|
||||
@ -51,7 +51,7 @@ const ACTION_DESCRIPTIONS: Record<string, string> = {
|
||||
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',
|
||||
|
||||
@ -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' });
|
||||
}
|
||||
};
|
||||
|
||||
@ -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' });
|
||||
|
||||
@ -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']
|
||||
|
||||
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user