made compatible t take serve frontend build

This commit is contained in:
laxman h 2026-04-27 19:51:46 +05:30
parent 4037f68745
commit a9018ab0ff
7 changed files with 1072 additions and 272 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

14
build/index.html Normal file
View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Royal Enfield Onboarding</title>
<script type="module" crossorigin src="/assets/index-CAe70IkM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DkEVuJwH.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View File

@ -6,6 +6,7 @@ import compression from 'compression';
import rateLimit from 'express-rate-limit'; import rateLimit from 'express-rate-limit';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import fs from 'fs';
import { createServer } from 'http'; import { createServer } from 'http';
import { initSocket } from './common/utils/socket.js'; import { initSocket } from './common/utils/socket.js';
@ -46,6 +47,9 @@ import logger from './common/utils/logger.js';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
const frontendBuildPath = path.resolve(process.cwd(), 'build');
const frontendIndexPath = path.join(frontendBuildPath, 'index.html');
const hasFrontendBuild = fs.existsSync(frontendIndexPath);
// Initialize Express app // Initialize Express app
const app = express(); const app = express();
@ -65,8 +69,16 @@ app.use(helmet({
crossOriginEmbedderPolicy: false, crossOriginEmbedderPolicy: false,
crossOriginResourcePolicy: { policy: "cross-origin" } crossOriginResourcePolicy: { policy: "cross-origin" }
})); }));
const allowedOrigins = new Set<string>([
process.env.FRONTEND_URL || 'http://localhost:5173',
'http://localhost:5173'
]);
app.use(cors({ app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:5173', origin: (origin, callback) => {
// Allow same-origin/browser requests without explicit Origin and known frontend origins.
if (!origin || allowedOrigins.has(origin)) return callback(null, true);
return callback(null, false);
},
credentials: true credentials: true
})); }));
@ -146,11 +158,27 @@ app.use('/api/dealers', dealerRoutes);
app.use('/api/finance', settlementRoutes); app.use('/api/finance', settlementRoutes);
app.use('/api/worknotes', collaborationRoutes); app.use('/api/worknotes', collaborationRoutes);
// Serve React build from backend in single-domain deployments.
if (hasFrontendBuild) {
app.use(express.static(frontendBuildPath));
}
// 404 handler // 404 handler
app.use((req: Request, res: Response) => { app.use((req: Request, res: Response) => {
res.status(404).json({ if (req.path.startsWith('/api')) {
return res.status(404).json({
success: false,
message: 'Route not found'
});
}
if (hasFrontendBuild) {
return res.sendFile(frontendIndexPath);
}
return res.status(404).json({
success: false, success: false,
message: 'Route not found' message: 'Route not found'
}); });

View File

@ -264,312 +264,312 @@ async function triggerWorkflow() {
}, leadToken); }, leadToken);
const interviewId2 = intv2Response.data.id; const interviewId2 = intv2Response.data.id;
log(5.1, 'DD-Lead Giving Feedback...'); // log(5.1, 'DD-Lead Giving Feedback...');
await apiRequest('/assessment/level2-feedback', 'POST', { // await apiRequest('/assessment/level2-feedback', 'POST', {
interviewId: interviewId2, // interviewId: interviewId2,
overallScore: 9.5, // overallScore: 9.5,
feedbackItems: [ // feedbackItems: [
{ type: 'Strategic Vision', comments: 'Excellent strategic planning.' }, // { type: 'Strategic Vision', comments: 'Excellent strategic planning.' },
{ type: 'Management Capabilities', comments: 'Strong team leadership.' }, // { type: 'Management Capabilities', comments: 'Strong team leadership.' },
{ type: 'Operational Understanding', comments: 'Knows the local market well.' } // { type: 'Operational Understanding', comments: 'Knows the local market well.' }
], // ],
recommendation: 'Selected' // recommendation: 'Selected'
}, leadToken); // }, leadToken);
log(5.15, 'ZBH Giving Feedback...'); // log(5.15, 'ZBH Giving Feedback...');
const zbhToken = await login(zbhUser.email); // const zbhToken = await login(zbhUser.email);
await apiRequest('/assessment/level2-feedback', 'POST', { // await apiRequest('/assessment/level2-feedback', 'POST', {
interviewId: interviewId2, // interviewId: interviewId2,
overallScore: 9.0, // overallScore: 9.0,
feedbackItems: [ // feedbackItems: [
{ type: 'Strategic Vision', comments: 'Good alignment with brand.' }, // { type: 'Strategic Vision', comments: 'Good alignment with brand.' },
{ type: 'Key Strengths', comments: 'Great location proposed.' }, // { type: 'Key Strengths', comments: 'Great location proposed.' },
{ type: 'Areas of Concern', comments: 'None at this time.' } // { type: 'Areas of Concern', comments: 'None at this time.' }
], // ],
recommendation: 'Selected' // recommendation: 'Selected'
}, zbhToken); // }, zbhToken);
log(5.2, 'DD-Lead Finalizing Level 2 Decision...'); // log(5.2, 'DD-Lead Finalizing Level 2 Decision...');
await apiRequest('/assessment/decision', 'POST', { // await apiRequest('/assessment/decision', 'POST', {
interviewId: interviewId2, // interviewId: interviewId2,
decision: 'Approved', // decision: 'Approved',
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...');
const fddUser = users.data.find(u => u.email === EMAILS.FDD); // const fddUser = users.data.find(u => u.email === EMAILS.FDD);
await apiRequest('/fdd/assign', 'POST', { // await apiRequest('/fdd/assign', 'POST', {
applicationId: applicationUUID, // applicationId: applicationUUID,
assignedToAgency: fddUser.id // assignedToAgency: fddUser.id
}, adminToken); // }, adminToken);
log(6.3, 'FDD Agency assigned successfully.'); // log(6.3, 'FDD Agency assigned successfully.');
await delay(); // await delay();
// 7. FDD MILESTONE // // 7. FDD MILESTONE
log(7, 'FDD Agency Discovery & Report Upload...'); // log(7, 'FDD Agency Discovery & Report Upload...');
const fddToken = await login(EMAILS.FDD); // const fddToken = await login(EMAILS.FDD);
// FETCH ASSIGNMENT ID // // FETCH ASSIGNMENT ID
const assignmentRes = await apiRequest(`/fdd/${applicationUUID}`, 'GET', null, fddToken); // const assignmentRes = await apiRequest(`/fdd/${applicationUUID}`, 'GET', null, fddToken);
const assignmentId = assignmentRes.data.id; // const assignmentId = assignmentRes.data.id;
log(7, `Found Assignment ID: ${assignmentId}`); // log(7, `Found Assignment ID: ${assignmentId}`);
await apiRequest('/fdd/report', 'POST', { // await apiRequest('/fdd/report', 'POST', {
assignmentId, // assignmentId,
findings: 'Finance records clean.', // findings: 'Finance records clean.',
recommendation: 'Approved' // recommendation: 'Approved'
}, fddToken); // }, fddToken);
log(7.1, 'Admin Approving FDD Final Stage...'); // log(7.1, 'Admin Approving FDD Final Stage...');
await apiRequest('/assessment/stage-decision', 'POST', { // await apiRequest('/assessment/stage-decision', 'POST', {
applicationId: applicationUUID, // applicationId: applicationUUID,
stageCode: 'FDD_VERIFICATION', // stageCode: 'FDD_VERIFICATION',
decision: 'Approved', // decision: 'Approved',
remarks: 'FDD documents verified.' // remarks: 'FDD documents verified.'
}, adminToken); // }, adminToken);
log(7, 'FDD Milestone Complete.'); // log(7, 'FDD Milestone Complete.');
await delay(); // await delay();
log(7.4, 'Uploading mandatory documents prior to LOI generation...'); // log(7.4, 'Uploading mandatory documents prior to LOI generation...');
const requiredDocs = ['CIBIL Report', 'Proposed Site City Map', 'Bank Statement', 'GST Certificate', 'PAN Card']; // const requiredDocs = ['CIBIL Report', 'Proposed Site City Map', 'Bank Statement', 'GST Certificate', 'PAN Card'];
for (const doc of requiredDocs) { // for (const doc of requiredDocs) {
await mockUploadDocument(applicationUUID, adminToken, doc); // await mockUploadDocument(applicationUUID, adminToken, doc);
} // }
await delay(1000); // await delay(1000);
// 7.5 LOI APPROVAL // // 7.5 LOI APPROVAL
log(7.5, 'LOI Generation & Approval...'); // log(7.5, 'LOI Generation & Approval...');
const loiRes = await apiRequest('/loi/request', 'POST', { applicationId: applicationUUID }, adminToken); // const loiRes = await apiRequest('/loi/request', 'POST', { applicationId: applicationUUID }, adminToken);
const loiRequestId = loiRes.data.id; // const loiRequestId = loiRes.data.id;
// Head Approval // // Head Approval
await apiRequest(`/loi/request/${loiRequestId}/approve`, 'POST', { // await apiRequest(`/loi/request/${loiRequestId}/approve`, 'POST', {
action: 'Approved', // action: 'Approved',
remarks: 'Head Authorization for LOI' // remarks: 'Head Authorization for LOI'
}, headToken); // }, headToken);
// NBH Approval // // NBH Approval
await apiRequest(`/loi/request/${loiRequestId}/approve`, 'POST', { // await apiRequest(`/loi/request/${loiRequestId}/approve`, 'POST', {
action: 'Approved', // action: 'Approved',
remarks: 'NBH Authorization for LOI' // remarks: 'NBH Authorization for LOI'
}, nbhToken); // }, nbhToken);
log(7.5, 'LOI Milestone Complete.'); // log(7.5, 'LOI Milestone Complete.');
await delay(); // await delay();
// 8. PAYMENT GATE (SECURITY DEPOSIT FIRST AS PER CURRENT FLOW) // // 8. PAYMENT GATE (SECURITY DEPOSIT FIRST AS PER CURRENT FLOW)
log(8, 'Finance Verifying SECURITY_DEPOSIT to unlock LOI Issued...'); // log(8, 'Finance Verifying SECURITY_DEPOSIT to unlock LOI Issued...');
const financeToken = await login(EMAILS.FINANCE); // const financeToken = await login(EMAILS.FINANCE);
await apiRequest('/loa/security-deposit', 'POST', { // await apiRequest('/loa/security-deposit', 'POST', {
applicationId: applicationUUID, // applicationId: applicationUUID,
amount: 500000, // amount: 500000,
paymentReference: 'PAY-888999', // paymentReference: 'PAY-888999',
depositType: 'SECURITY_DEPOSIT', // depositType: 'SECURITY_DEPOSIT',
status: 'Verified' // status: 'Verified'
}, financeToken); // }, financeToken);
log(8, 'Security Deposit Verified.') // log(8, 'Security Deposit Verified.')
// 9. GENERATE DEALER CODES (align with backend gate: LOI Issued required) // // 9. GENERATE DEALER CODES (align with backend gate: LOI Issued required)
let statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken); // let statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);
log(9, `Current status before code generation: ${statusBeforeCodeGen}`); // log(9, `Current status before code generation: ${statusBeforeCodeGen}`);
log(9, 'Ensuring mandatory PAN/GST/Bank fields before code generation...'); // log(9, 'Ensuring mandatory PAN/GST/Bank fields before code generation...');
await ensureMandatoryCodeGenFields(applicationUUID, adminToken); // await ensureMandatoryCodeGenFields(applicationUUID, adminToken);
await delay(300); // await delay(300);
if (statusBeforeCodeGen === 'Security Details') { // if (statusBeforeCodeGen === 'Security Details') {
log(9, 'Status is Security Details; re-verifying Security Deposit to move to LOI Issued...'); // log(9, 'Status is Security Details; re-verifying Security Deposit to move to LOI Issued...');
await apiRequest('/loa/security-deposit', 'POST', { // await apiRequest('/loa/security-deposit', 'POST', {
applicationId: applicationUUID, // applicationId: applicationUUID,
amount: 500000, // amount: 500000,
paymentReference: `PAY-RETRY-${Date.now()}`, // paymentReference: `PAY-RETRY-${Date.now()}`,
depositType: 'SECURITY_DEPOSIT', // depositType: 'SECURITY_DEPOSIT',
status: 'Verified' // status: 'Verified'
}, financeToken); // }, financeToken);
await delay(); // await delay();
statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken); // statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);
log(9, `Status after re-verify: ${statusBeforeCodeGen}`); // log(9, `Status after re-verify: ${statusBeforeCodeGen}`);
} // }
// Current backend flow keeps app at "Security Details" until explicit admin transition. // // Current backend flow keeps app at "Security Details" until explicit admin transition.
if (statusBeforeCodeGen === 'Security Details') { // if (statusBeforeCodeGen === 'Security Details') {
log(9, 'Applying admin transition from Security Details -> LOI Issued...'); // log(9, 'Applying admin transition from Security Details -> LOI Issued...');
await apiRequest(`/onboarding/applications/${applicationUUID}/status`, 'PUT', { // await apiRequest(`/onboarding/applications/${applicationUUID}/status`, 'PUT', {
status: 'LOI Issued', // status: 'LOI Issued',
stage: 'LOI', // stage: 'LOI',
reason: 'E2E script alignment: unlock dealer code generation after Security Details checks.' // reason: 'E2E script alignment: unlock dealer code generation after Security Details checks.'
}, adminToken); // }, adminToken);
await delay(); // await delay();
statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken); // statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);
log(9, `Status after admin transition: ${statusBeforeCodeGen}`); // log(9, `Status after admin transition: ${statusBeforeCodeGen}`);
} // }
if (statusBeforeCodeGen !== 'LOI Issued' && statusBeforeCodeGen !== 'Dealer Code Generation') { // if (statusBeforeCodeGen !== 'LOI Issued' && statusBeforeCodeGen !== 'Dealer Code Generation') {
throw new Error(`Cannot generate codes: expected LOI Issued/Dealer Code Generation, got ${statusBeforeCodeGen}`); // throw new Error(`Cannot generate codes: expected LOI Issued/Dealer Code Generation, got ${statusBeforeCodeGen}`);
} // }
log(9, 'Admin Generating SAP Dealer Codes...'); // log(9, 'Admin Generating SAP Dealer Codes...');
await apiRequest(`/onboarding/applications/${applicationUUID}/generate-codes`, 'POST', {}, adminToken); // await apiRequest(`/onboarding/applications/${applicationUUID}/generate-codes`, 'POST', {}, adminToken);
log(9, 'Dealer Codes Generated.'); // log(9, 'Dealer Codes Generated.');
await delay(); // await delay();
// 10. FIRST FILL (POST CODE-GENERATION) // // 10. FIRST FILL (POST CODE-GENERATION)
log(10, 'Finance Verifying FIRST FILL (₹15L)...'); // log(10, 'Finance Verifying FIRST FILL (₹15L)...');
await apiRequest('/loa/security-deposit', 'POST', { // await apiRequest('/loa/security-deposit', 'POST', {
applicationId: applicationUUID, // applicationId: applicationUUID,
amount: 1500000, // amount: 1500000,
paymentReference: 'PAY-FIN-999', // paymentReference: 'PAY-FIN-999',
depositType: 'FIRST_FILL', // depositType: 'FIRST_FILL',
status: 'Verified' // status: 'Verified'
}, financeToken); // }, financeToken);
log(10, 'Final Security Deposit Verified.'); // log(10, 'Final Security Deposit Verified.');
await delay(); // await delay();
// 11. ADMIN UPDATING STATUTORY & BANK DETAILS // // 11. ADMIN UPDATING STATUTORY & BANK DETAILS
log(11, 'Admin Updating Statutory & Bank Details for LOA Approval Gate...'); // log(11, 'Admin Updating Statutory & Bank Details for LOA Approval Gate...');
await apiRequest(`/onboarding/applications/${applicationUUID}`, 'PUT', { // await apiRequest(`/onboarding/applications/${applicationUUID}`, 'PUT', {
accountHolderName: 'Ramesh Automobiles Private Limited', // accountHolderName: 'Ramesh Automobiles Private Limited',
panNumber: 'ABCDE1234F', // panNumber: 'ABCDE1234F',
gstNumber: '07ABCDE1234F1Z5', // gstNumber: '07ABCDE1234F1Z5',
bankName: 'HDFC Bank', // bankName: 'HDFC Bank',
accountNumber: '50100223344556', // accountNumber: '50100223344556',
ifscCode: 'HDFC0001234' // ifscCode: 'HDFC0001234'
}, adminToken); // }, adminToken);
log(11, 'Statutory & Bank details updated.'); // log(11, 'Statutory & Bank details updated.');
await delay(); // await delay();
// 12. FINAL LOA APPROVAL // // 12. FINAL LOA APPROVAL
log(12, 'NBH & Head Approving Final LOA...'); // log(12, 'NBH & Head Approving Final LOA...');
const loaRes = await apiRequest('/loa/request', 'POST', { applicationId: applicationUUID }, headToken); // const loaRes = await apiRequest('/loa/request', 'POST', { applicationId: applicationUUID }, headToken);
const finalLoaRequestId = loaRes.data.id; // const finalLoaRequestId = loaRes.data.id;
await apiRequest(`/loa/request/${finalLoaRequestId}/approve`, 'POST', { // await apiRequest(`/loa/request/${finalLoaRequestId}/approve`, 'POST', {
action: 'Approved', // action: 'Approved',
remarks: 'Head Authorization (Level 1)' // remarks: 'Head Authorization (Level 1)'
}, headToken); // }, headToken);
await apiRequest(`/loa/request/${finalLoaRequestId}/approve`, 'POST', { // await apiRequest(`/loa/request/${finalLoaRequestId}/approve`, 'POST', {
action: 'Approved', // action: 'Approved',
remarks: 'NBH Approval (Level 2)' // remarks: 'NBH Approval (Level 2)'
}, nbhToken); // }, nbhToken);
log(12, 'LOA Fully Approved.'); // log(12, 'LOA Fully Approved.');
await delay(); // await delay();
// 13. EOR (EVIDENCE OF READINESS) CHECKLIST VERIFICATION // // 13. EOR (EVIDENCE OF READINESS) CHECKLIST VERIFICATION
log(13, 'Admin Initializing EOR Checklist (100% Readiness Requirement)...'); // log(13, 'Admin Initializing EOR Checklist (100% Readiness Requirement)...');
const eorInit = await apiRequest('/eor', 'POST', { applicationId: applicationUUID }, adminToken); // const eorInit = await apiRequest('/eor', 'POST', { applicationId: applicationUUID }, adminToken);
const checklistId = eorInit.data.id; // const checklistId = eorInit.data.id;
log(13, `EOR Checklist Created (ID: ${checklistId})`); // log(13, `EOR Checklist Created (ID: ${checklistId})`);
log(13.1, 'Auditor Verifying all 12 mandatory EOR items as COMPLIANT...'); // log(13.1, 'Auditor Verifying all 12 mandatory EOR items as COMPLIANT...');
const eorItems = [ // const eorItems = [
{ itemType: 'Sales', description: 'Sales Standards' }, // { itemType: 'Sales', description: 'Sales Standards' },
{ itemType: 'Service', description: 'Service & Spares' }, // { itemType: 'Service', description: 'Service & Spares' },
{ itemType: 'IT', description: 'DMS infra' }, // { itemType: 'IT', description: 'DMS infra' },
{ itemType: 'Training', description: 'Manpower Training' }, // { itemType: 'Training', description: 'Manpower Training' },
{ itemType: 'Statutory', description: 'Trade certificate with test ride bikes registration' }, // { itemType: 'Statutory', description: 'Trade certificate with test ride bikes registration' },
{ itemType: 'Statutory', description: 'GST certificate including Accessories & Apparels billing' }, // { itemType: 'Statutory', description: 'GST certificate including Accessories & Apparels billing' },
{ itemType: 'Finance', description: 'Inventory Funding' }, // { itemType: 'Finance', description: 'Inventory Funding' },
{ itemType: 'IT', description: 'Virtual code availability' }, // { itemType: 'IT', description: 'Virtual code availability' },
{ itemType: 'Finance', description: 'Vendor payments' }, // { itemType: 'Finance', description: 'Vendor payments' },
{ itemType: 'Marketing', description: 'Details for website submission' }, // { itemType: 'Marketing', description: 'Details for website submission' },
{ itemType: 'Insurance', description: 'Infra Insurance both Showroom and Service center' }, // { itemType: 'Insurance', description: 'Infra Insurance both Showroom and Service center' },
{ itemType: 'IT', description: 'Auto ordering' } // { itemType: 'IT', description: 'Auto ordering' }
]; // ];
for (const item of eorItems) { // for (const item of eorItems) {
process.stdout.write(`.`); // Visual progress // process.stdout.write(`.`); // Visual progress
await apiRequest(`/eor/item/${checklistId}`, 'POST', { // await apiRequest(`/eor/item/${checklistId}`, 'POST', {
...item, // ...item,
isCompliant: true, // isCompliant: true,
remarks: 'Verified by Auditor - Compliant' // remarks: 'Verified by Auditor - Compliant'
}, adminToken); // }, adminToken);
} // }
console.log('\n[STEP 13.1] All EOR items marked as compliant.'); // console.log('\n[STEP 13.1] All EOR items marked as compliant.');
log(13.2, 'Auditor Submitting Final EOR Audit...'); // log(13.2, 'Auditor Submitting Final EOR Audit...');
await apiRequest(`/eor/audit/${checklistId}`, 'POST', { // await apiRequest(`/eor/audit/${checklistId}`, 'POST', {
status: 'Completed', // status: 'Completed',
overallComments: 'Dealer is 100% ready for inauguration. All infra and statutory items verified.' // overallComments: 'Dealer is 100% ready for inauguration. All infra and statutory items verified.'
}, adminToken); // }, adminToken);
// Status check // // Status check
const finalAppStatus = await apiRequest(`/onboarding/applications/${applicationUUID}`, 'GET', null, adminToken); // const finalAppStatus = await apiRequest(`/onboarding/applications/${applicationUUID}`, 'GET', null, adminToken);
log(13.2, `Application Status after EOR: ${finalAppStatus.data.overallStatus}`); // log(13.2, `Application Status after EOR: ${finalAppStatus.data.overallStatus}`);
await delay(); // await delay();
// 14. FINAL ONBOARDING // // 14. FINAL ONBOARDING
log(14, 'Admin Finalizing Dealer Onboarding...'); // log(14, 'Admin Finalizing Dealer Onboarding...');
await apiRequest('/dealers', 'POST', { applicationId: applicationUUID }, adminToken); // await apiRequest('/dealers', 'POST', { applicationId: applicationUUID }, adminToken);
await delay(); // await delay();
// 15. VERIFICATION // // 15. VERIFICATION
log(15, 'Verifying Dealer Record Creation...'); // log(15, 'Verifying Dealer Record Creation...');
const dealerRes = await apiRequest(`/dealers/application/${applicationUUID}`, 'GET', null, adminToken); // const dealerRes = await apiRequest(`/dealers/application/${applicationUUID}`, 'GET', null, adminToken);
if (!dealerRes.success || !dealerRes.data) { // if (!dealerRes.success || !dealerRes.data) {
throw new Error('Verification Failed: Dealer record not found after onboarding.'); // throw new Error('Verification Failed: Dealer record not found after onboarding.');
} // }
log(15, `Dealer Found: ${dealerRes.data.legalName} (${dealerRes.data.id})`); // log(15, `Dealer Found: ${dealerRes.data.legalName} (${dealerRes.data.id})`);
log(15.1, 'Verifying User Account Role Update...'); // log(15.1, 'Verifying User Account Role Update...');
const userRes = await apiRequest(`/admin/users`, 'GET', null, adminToken); // const userRes = await apiRequest(`/admin/users`, 'GET', null, adminToken);
const dealerUser = userRes.data.find(u => u.email === PROSPECT_EMAIL); // const dealerUser = userRes.data.find(u => u.email === PROSPECT_EMAIL);
if (!dealerUser || dealerUser.roleCode !== 'Dealer') { // if (!dealerUser || dealerUser.roleCode !== 'Dealer') {
throw new Error(`Verification Failed: User role not updated to 'Dealer'. Current role: ${dealerUser?.roleCode}`); // throw new Error(`Verification Failed: User role not updated to 'Dealer'. Current role: ${dealerUser?.roleCode}`);
} // }
log(15.1, `User role confirmed: ${dealerUser.roleCode}`); // log(15.1, `User role confirmed: ${dealerUser.roleCode}`);
log(15.2, '--- WORKFLOW COMPLETED SUCCESSFULLY! ---'); // log(15.2, '--- WORKFLOW COMPLETED SUCCESSFULLY! ---');
log(15.2, `The application ${applicationId} is now at 'ONBOARDED' status and Dealer profile is active.`); // log(15.2, `The application ${applicationId} is now at 'ONBOARDED' status and Dealer profile is active.`);
} }
/** /**