started removing document type dependecy and f&F screeen bug changes fixed

This commit is contained in:
Laxman 2026-05-19 21:25:24 +05:30
parent f5d7ccc1ab
commit 9c6c585073
6 changed files with 132 additions and 58 deletions

View File

@ -2410,7 +2410,7 @@ documentation and AI recommendation summary.
o FDD (Financial Due Diligence): Handled by the FDD partner for financial validation; o FDD (Financial Due Diligence): Handled by the FDD partner for financial validation;
documents uploaded for review. documents uploaded for review.
o LOI Approval: Preparation and verification for Letter of Intent issuance. o LOI Approval: Preparation and verification for Letter of Intent issuance.
o Security Details: Security and compliance document verification stage. o Security Deposit: Security and compliance document verification stage.
o LOI Issue: Formal Letter of Intent generated and uploaded. o LOI Issue: Formal Letter of Intent generated and uploaded.
o Dealer Code Generation : Dealer Code creation is initiated upon trigger by the DD- o Dealer Code Generation : Dealer Code creation is initiated upon trigger by the DD-
Admin , created in the SAP Master , and logged against the application for audit Admin , created in the SAP Master , and logged against the application for audit

View File

@ -0,0 +1,83 @@
/**
* Migration Script: Clean up onboarding_documents table.
*
* What it does (idempotent safe to re-run):
* 1. Drops legacy columns `requestId` and `requestType` (and their indexes).
* These were generic catch-alls from when a single documents table routed
* across modules. Each module now has its own dedicated documents table
* (resignation_documents, termination_documents, constitutional_documents,
* relocation_documents), so these columns are dead weight on
* onboarding_documents and are not read or written anywhere in code.
* 2. Adds two indexes the UI actually queries:
* - (applicationId, stage) -> Progress / Documents tab grouping
* - documentType -> EOR auto-link in onboarding.controller.ts
*
* What it does NOT do:
* - No new "documentName" column. The user-entered document name is sent as
* the FormData filename and stored in the existing `fileName` column.
* - Does not touch `dealerId` (the Dealer <-> OnboardingDocument association
* references it; it stays for future use).
*
* Run: npx tsx scripts/migrate-onboarding-documents-cleanup.ts
*/
import 'dotenv/config';
import db from '../src/database/models/index.js';
const TABLE = 'onboarding_documents';
async function migrate() {
const queryInterface = db.sequelize.getQueryInterface();
try {
console.log(`🔄 Cleaning up ${TABLE} ...\n`);
await db.sequelize.authenticate();
const tableInfo = await queryInterface.describeTable(TABLE);
// 1) Drop the index on requestId first (if it exists). Index name depends on
// how Sequelize/Postgres generated it — try the common variants.
for (const idxName of [
`${TABLE}_requestId`,
`${TABLE}_request_id`,
]) {
try {
await db.sequelize.query(`DROP INDEX IF EXISTS "${idxName}"`);
console.log(`✓ Dropped index ${idxName} (if existed)`);
} catch (err: any) {
console.log(`- Skipped index ${idxName}: ${err.message}`);
}
}
// 2) Drop the unused columns (idempotent via describeTable check).
for (const col of ['requestId', 'requestType']) {
if (tableInfo[col]) {
console.log(`Dropping column ${col} ...`);
await queryInterface.removeColumn(TABLE, col);
console.log(`✓ Dropped column ${col}`);
} else {
console.log(`- Column ${col} not present (already cleaned)`);
}
}
// 3) Add useful indexes (idempotent — Postgres IF NOT EXISTS).
await db.sequelize.query(
`CREATE INDEX IF NOT EXISTS "${TABLE}_applicationId_stage" ON ${TABLE} ("applicationId", "stage")`
);
console.log(`✓ Ensured index ${TABLE}_applicationId_stage`);
await db.sequelize.query(
`CREATE INDEX IF NOT EXISTS "${TABLE}_documentType" ON ${TABLE} ("documentType")`
);
console.log(`✓ Ensured index ${TABLE}_documentType`);
console.log('\n✅ Migration completed successfully!');
} catch (error: any) {
console.error('\n❌ Migration failed:', error.message);
if (error.stack) console.error('\nStack Trace:\n', error.stack);
process.exit(1);
} finally {
await db.sequelize.close();
}
}
migrate();

View File

@ -5,8 +5,6 @@ export interface DocumentAttributes {
id: string; id: string;
applicationId: string | null; applicationId: string | null;
dealerId: string | null; dealerId: string | null;
requestId: string | null; // Compatibility
requestType: string | null; // Compatibility
documentType: string; documentType: string;
fileName: string; fileName: string;
filePath: string; filePath: string;
@ -42,14 +40,6 @@ export default (sequelize: Sequelize) => {
key: 'id' key: 'id'
} }
}, },
requestId: {
type: DataTypes.UUID,
allowNull: true
},
requestType: {
type: DataTypes.STRING,
allowNull: true
},
documentType: { documentType: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false allowNull: false
@ -92,7 +82,8 @@ export default (sequelize: Sequelize) => {
indexes: [ indexes: [
{ fields: ['applicationId'] }, { fields: ['applicationId'] },
{ fields: ['dealerId'] }, { fields: ['dealerId'] },
{ fields: ['requestId'] } { fields: ['applicationId', 'stage'] },
{ fields: ['documentType'] }
] ]
}); });

View File

@ -1051,7 +1051,7 @@ export const updateResignationStatus = async (req: AuthRequest, res: Response, n
return sendBackResignation(req, res, next); return sendBackResignation(req, res, next);
case 'pushfnf': case 'pushfnf':
// Verify if user role is authorized for manual jump to F&F // Verify if user role is authorized for manual jump to F&F
const authorizedRoles = [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.NBH, ROLES.DD_ADMIN, ROLES.SUPER_ADMIN]; const authorizedRoles = [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.DD_ADMIN, ROLES.SUPER_ADMIN];
if (!req.user || !authorizedRoles.includes(req.user.roleCode as any)) { if (!req.user || !authorizedRoles.includes(req.user.roleCode as any)) {
return res.status(403).json({ success: false, message: 'You do not have permission to push this request to F&F' }); return res.status(403).json({ success: false, message: 'You do not have permission to push this request to F&F' });
} }

View File

@ -166,7 +166,7 @@ export class ResignationWorkflowService {
[RESIGNATION_STAGES.NBH]: ROLES.NBH, [RESIGNATION_STAGES.NBH]: ROLES.NBH,
[RESIGNATION_STAGES.LEGAL]: ROLES.LEGAL_ADMIN, [RESIGNATION_STAGES.LEGAL]: ROLES.LEGAL_ADMIN,
[RESIGNATION_STAGES.DD_ADMIN]: ROLES.DD_ADMIN, [RESIGNATION_STAGES.DD_ADMIN]: ROLES.DD_ADMIN,
[RESIGNATION_STAGES.AWAITING_FNF]: [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.NBH, ROLES.DD_ADMIN], [RESIGNATION_STAGES.AWAITING_FNF]: [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.DD_ADMIN],
[RESIGNATION_STAGES.FNF_INITIATED]: ROLES.DD_ADMIN [RESIGNATION_STAGES.FNF_INITIATED]: ROLES.DD_ADMIN
}; };

View File

@ -296,55 +296,55 @@ async function triggerWorkflow() {
remarks: 'Cleared Level 2' remarks: 'Cleared Level 2'
}, leadToken); }, leadToken);
log(5, 'Level 2 Complete.'); log(5, 'Level 2 Complete.');
// await delay(); await delay();
// // 6. LEVEL-3 INTERVIEW // 6. LEVEL-3 INTERVIEW
// log(6, 'Scheduling Level 3 Interview...'); log(6, 'Scheduling Level 3 Interview...');
// const headUser = users.data.find(u => u.email === EMAILS.DD_HEAD); const headUser = users.data.find(u => u.email === EMAILS.DD_HEAD);
// const nbhUser = users.data.find(u => u.email === EMAILS.NBH); const nbhUser = users.data.find(u => u.email === EMAILS.NBH);
// const intv3Response = await apiRequest('/assessment/interviews', 'POST', { const intv3Response = await apiRequest('/assessment/interviews', 'POST', {
// applicationId: applicationUUID, applicationId: applicationUUID,
// level: 3, level: 3,
// scheduledAt: new Date(Date.now() + 259200000).toISOString(), scheduledAt: new Date(Date.now() + 259200000).toISOString(),
// type: 'In-Person', type: 'In-Person',
// location: 'HO', location: 'HO',
// participants: [headUser.id, nbhUser.id] participants: [headUser.id, nbhUser.id]
// }, leadToken); }, leadToken);
// const interviewId3 = intv3Response.data.id; const interviewId3 = intv3Response.data.id;
// log(6.1, 'NBH Giving Feedback...'); log(6.1, 'NBH Giving Feedback...');
// const nbhToken = await login(EMAILS.NBH); const nbhToken = await login(EMAILS.NBH);
// await apiRequest('/assessment/level2-feedback', 'POST', { await apiRequest('/assessment/level2-feedback', 'POST', {
// interviewId: interviewId3, interviewId: interviewId3,
// overallScore: 10, overallScore: 10,
// feedbackItems: [ feedbackItems: [
// { type: 'Business Vision & Strategy', comments: 'Highly recommended for this market.' }, { type: 'Business Vision & Strategy', comments: 'Highly recommended for this market.' },
// { type: 'Leadership & Decision Making', comments: 'Shows great potential.' } { type: 'Leadership & Decision Making', comments: 'Shows great potential.' }
// ], ],
// recommendation: 'Selected' recommendation: 'Selected'
// }, nbhToken); }, nbhToken);
// log(6.15, 'DD-Head Giving Feedback...'); log(6.15, 'DD-Head Giving Feedback...');
// const headToken = await login(EMAILS.DD_HEAD); const headToken = await login(EMAILS.DD_HEAD);
// await apiRequest('/assessment/level2-feedback', 'POST', { await apiRequest('/assessment/level2-feedback', 'POST', {
// interviewId: interviewId3, interviewId: interviewId3,
// overallScore: 9.5, overallScore: 9.5,
// feedbackItems: [ feedbackItems: [
// { type: 'Operational & Financial Readiness', comments: 'Financially sound.' }, { type: 'Operational & Financial Readiness', comments: 'Financially sound.' },
// { type: 'Brand Alignment', comments: 'Understands Royal Enfield ethos perfectly.' } { type: 'Brand Alignment', comments: 'Understands Royal Enfield ethos perfectly.' }
// ], ],
// recommendation: 'Selected' recommendation: 'Selected'
// }, headToken); }, headToken);
// log(6.2, 'Head Finalizing Level 3 Decision...'); log(6.2, 'Head Finalizing Level 3 Decision...');
// await apiRequest('/assessment/decision', 'POST', { await apiRequest('/assessment/decision', 'POST', {
// interviewId: interviewId3, interviewId: interviewId3,
// decision: 'Approved', decision: 'Approved',
// remarks: 'Cleared Level 3. Moving to FDD.' remarks: 'Cleared Level 3. Moving to FDD.'
// }, headToken); }, headToken);
// log(6, 'Level 3 Complete. Stage is now FDD Verification.'); log(6, 'Level 3 Complete. Stage is now FDD Verification.');
// await delay(); await delay();
// // 6.3 FDD ASSIGNMENT // // 6.3 FDD ASSIGNMENT
// log(6.3, 'Admin Assigning Application to FDD Agency...'); // log(6.3, 'Admin Assigning Application to FDD Agency...');