583 lines
23 KiB
JavaScript
583 lines
23 KiB
JavaScript
/**
|
|
* ROYAL ENFIELD DEALER ONBOARDING - END-TO-END WORKFLOW TRIGGER
|
|
* This script automates the entire journey from Application to LOA.
|
|
*/
|
|
|
|
import fs from 'fs';
|
|
const args = Object.fromEntries(
|
|
process.argv.slice(2)
|
|
.map(arg => arg.replace(/^--/, '').split('='))
|
|
.map(([k, v]) => [k, v ?? 'true'])
|
|
);
|
|
const BASE_URL = args.baseUrl || process.env.BASE_URL || 'http://localhost:5000/api';
|
|
const PASSWORD = 'Admin@123';
|
|
const OTP = '123456';
|
|
const STEP_DELAY_MS = Number(args.delayMs || 1000);
|
|
|
|
// Append timestamp to email to avoid duplicate application error
|
|
const timestamp = Date.now();
|
|
const PROSPECT_EMAIL = `ramesh_${timestamp}@gmail.com`;
|
|
|
|
const EMAILS = {
|
|
PROSPECT: PROSPECT_EMAIL,
|
|
RBM_L1: 'manish@royalenfield.com',
|
|
ZM_L1: 'piyush@royalenfield.com',
|
|
DD_LEAD: 'jaya@royalenfield.com',
|
|
ZBH: 'manav@royalenfield.com',
|
|
NBH: 'yashwin@royalenfield.com',
|
|
DD_HEAD: 'ganesh@royalenfield.com',
|
|
FDD: 'fdd@royalenfield.com',
|
|
FINANCE: 'finance@royalenfield.com',
|
|
DD_ADMIN: 'lince@royalenfield.com',
|
|
ASM: 'abhishek@royalenfield.com',
|
|
SALES: 'sales@royalenfield.com',
|
|
SERVICE: 'service@royalenfield.com',
|
|
SPARES: 'spares@royalenfield.com',
|
|
ACCOUNTS: 'accounts@royalenfield.com',
|
|
WARRANTY: 'warranty@royalenfield.com',
|
|
MARKETING: 'marketing@royalenfield.com',
|
|
HR: 'hr@royalenfield.com',
|
|
IT: 'it@royalenfield.com',
|
|
LEGAL: 'legal@royalenfield.com',
|
|
LOGISTICS: 'logistics@royalenfield.com',
|
|
QUALITY: 'quality@royalenfield.com',
|
|
APPAREL: 'apparel@royalenfield.com',
|
|
DMS: 'dms@royalenfield.com'
|
|
};
|
|
|
|
const PROSPECT_PAYLOAD = {
|
|
applicantName: "ramesh",
|
|
email: PROSPECT_EMAIL,
|
|
phone: "8197735918",
|
|
businessType: "Dealership",
|
|
locationType: "Urban",
|
|
district: "South Delhi",
|
|
city: "South Delhi",
|
|
state: "DELHI",
|
|
preferredLocation: "Indiranagar",
|
|
address: "123, 100ft Road",
|
|
pincode: "520038",
|
|
experienceYears: 5,
|
|
investmentCapacity: "2-3 Cr",
|
|
age: 32,
|
|
education: "MBA",
|
|
companyName: "Kumar Automobiles",
|
|
source: "Website",
|
|
existingDealer: "No",
|
|
ownRoyalEnfield: "Yes",
|
|
royalEnfieldModel: "Classic 350",
|
|
description: "Interested in opening a main dealership.",
|
|
panNumber: 'ABCDE1234F',
|
|
gstNumber: '07ABCDE1234F1Z5',
|
|
bankName: 'HDFC Bank',
|
|
accountNumber: '50100223344556',
|
|
ifscCode: 'HDFC0001234',
|
|
accountHolderName: 'Kumar Automobiles Private Limited',
|
|
registeredAddress: '123, Main Road, New Delhi'
|
|
};
|
|
|
|
// State to store IDs between steps
|
|
let applicationId = null;
|
|
let applicationUUID = null;
|
|
let interviewId = null;
|
|
let loaRequestId = null;
|
|
|
|
/**
|
|
* HELPERS
|
|
*/
|
|
const delay = (ms = STEP_DELAY_MS) => new Promise(res => setTimeout(res, ms));
|
|
|
|
const log = (step, msg) => console.log(`[STEP ${step}] ${msg}`);
|
|
|
|
async function apiRequest(endpoint, method = 'GET', body = null, token = null) {
|
|
const headers = { 'Content-Type': 'application/json' };
|
|
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
|
|
const config = { method, headers };
|
|
if (body) config.body = JSON.stringify(body);
|
|
|
|
const response = await fetch(`${BASE_URL}${endpoint}`, config);
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
console.error(`\x1b[31mFAIL: ${method} ${endpoint} returned ${response.status}\x1b[0m`);
|
|
console.error(JSON.stringify(data, null, 2));
|
|
process.exit(1);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
async function login(email) {
|
|
if (!login.cache) login.cache = {};
|
|
if (login.cache[email]) return login.cache[email];
|
|
const data = await apiRequest('/auth/login', 'POST', { email, password: PASSWORD });
|
|
login.cache[email] = data.token;
|
|
return login.cache[email]; // Standard login returns token at root
|
|
}
|
|
|
|
async function prospectLogin(phone) {
|
|
await apiRequest('/prospective-login/send-otp', 'POST', { phone });
|
|
const data = await apiRequest('/prospective-login/verify-otp', 'POST', { phone, otp: OTP });
|
|
return data.data.token; // Prospect OTP returns token inside data object
|
|
}
|
|
|
|
async function mockUploadDocument(appId, token, docType) {
|
|
const formData = new FormData();
|
|
const fileBuffer = fs.readFileSync('/home/laxman-h/Pictures/Screenshots/Screenshot from 2026-03-24 19-16-05.png');
|
|
const blob = new Blob([fileBuffer], { type: 'image/png' });
|
|
formData.append('file', blob, 'screenshot.png');
|
|
formData.append('documentType', docType);
|
|
|
|
const headers = { 'Authorization': `Bearer ${token}` };
|
|
const response = await fetch(`${BASE_URL}/onboarding/applications/${appId}/documents`, {
|
|
method: 'POST',
|
|
headers,
|
|
body: formData
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Upload Failed: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
async function getApplicationStatus(appId, token) {
|
|
const res = await apiRequest(`/onboarding/applications/${appId}`, 'GET', null, token);
|
|
return res?.data?.overallStatus || res?.data?.status || 'Unknown';
|
|
}
|
|
|
|
async function ensureMandatoryCodeGenFields(appId, token) {
|
|
const details = await apiRequest(`/onboarding/applications/${appId}`, 'GET', null, token);
|
|
const app = details?.data || {};
|
|
|
|
const fallbackFields = {
|
|
panNumber: app.panNumber || 'ABCDE1234F',
|
|
gstNumber: app.gstNumber || '07ABCDE1234F1Z5',
|
|
bankName: app.bankName || 'HDFC Bank',
|
|
accountNumber: app.accountNumber || '50100223344556',
|
|
ifscCode: app.ifscCode || 'HDFC0001234',
|
|
accountHolderName: app.accountHolderName || 'Kumar Automobiles Private Limited',
|
|
registeredAddress: app.registeredAddress || '123, Main Road, New Delhi'
|
|
};
|
|
|
|
await apiRequest(`/onboarding/applications/${appId}`, 'PUT', fallbackFields, token);
|
|
}
|
|
|
|
/**
|
|
* MAIN WORKFLOW
|
|
*/
|
|
async function triggerWorkflow() {
|
|
console.log('--- STARTING DEALER ONBOARDING E2E FLOW ---\n');
|
|
|
|
if (args.applicationId) {
|
|
applicationId = args.applicationId;
|
|
applicationUUID = args.applicationId;
|
|
log(1, `Resuming with existing application: ${applicationUUID}`);
|
|
} else {
|
|
// 1. PUBLIC APPLY
|
|
log(1, 'Public Prospect Application Submission...');
|
|
const appResponse = await apiRequest('/onboarding/apply', 'POST', PROSPECT_PAYLOAD);
|
|
applicationId = appResponse.data.applicationId;
|
|
applicationUUID = appResponse.data.id;
|
|
log(1, `Application Created: ${applicationId} (UUID: ${applicationUUID})`);
|
|
await delay();
|
|
}
|
|
|
|
// 2. ADMIN SHORTLIST
|
|
log(2, 'Admin Login & Shortlisting...');
|
|
const adminToken = await login(EMAILS.DD_ADMIN);
|
|
// Find the ASM to assign (just picking the first user with role DD-ASM if we could,
|
|
// but for now assigning to DD-Lead for testing)
|
|
const users = await apiRequest('/admin/users', 'GET', null, adminToken);
|
|
const ddLead = users.data.find(u => u.email === EMAILS.ASM);
|
|
|
|
await apiRequest('/onboarding/applications/shortlist', 'POST', {
|
|
applicationIds: [applicationId],
|
|
assignedTo: [ddLead.id],
|
|
remarks: 'Shortlisted for evaluation'
|
|
}, adminToken);
|
|
log(2, 'Application Shortlisted successfully.');
|
|
await delay();
|
|
|
|
// 3. SKIP QUESTIONNAIRE FOR TESTING STABILITY
|
|
log(3, 'Skipping Questionnaire stage for test stability...');
|
|
await delay();
|
|
|
|
// 4. LEVEL-1 INTERVIEW
|
|
log(4, 'ASM Scheduling Level 1 Interview...');
|
|
const leadToken = await login(EMAILS.DD_LEAD);
|
|
const rbmUser = users.data.find(u => u.email === EMAILS.RBM_L1);
|
|
const zmUser = users.data.find(u => u.email === EMAILS.ZM_L1);
|
|
const zbhUser = users.data.find(u => u.email === EMAILS.ZBH) || users.data[2];
|
|
|
|
const intvResponse = await apiRequest('/assessment/interviews', 'POST', {
|
|
applicationId: applicationUUID,
|
|
level: 1,
|
|
scheduledAt: new Date(Date.now() + 86400000).toISOString(),
|
|
type: 'In-Person',
|
|
location: 'Zonal Office',
|
|
participants: [rbmUser.id, zmUser.id]
|
|
}, leadToken);
|
|
interviewId = intvResponse.data.id;
|
|
log(4, `Level 1 Interview Scheduled (ID: ${interviewId})`);
|
|
await delay();
|
|
|
|
// FEEDBACK RBM
|
|
log(4.1, 'RBM Giving Feedback...');
|
|
const rbmToken = await login(EMAILS.RBM_L1);
|
|
await apiRequest('/assessment/kt-matrix', 'POST', {
|
|
interviewId,
|
|
criteriaScores: [{ criterionName: 'Business Acumen', score: 8.5, maxScore: 10, weightage: 100 }],
|
|
feedback: 'Strong business acumen.',
|
|
recommendation: 'Selected'
|
|
}, rbmToken);
|
|
|
|
// FEEDBACK ZM
|
|
log(4.2, 'ZM Giving Feedback...');
|
|
const zmToken = await login(EMAILS.ZM_L1);
|
|
await apiRequest('/assessment/kt-matrix', 'POST', {
|
|
interviewId,
|
|
criteriaScores: [{ criterionName: 'Vision', score: 9.0, maxScore: 10, weightage: 100 }],
|
|
feedback: 'Good vision for RE brand.',
|
|
recommendation: 'Selected'
|
|
}, zmToken);
|
|
|
|
// ZM DECISION (Rajesh Khanna)
|
|
log(4.3, 'ZM Finalizing Level 1 Decision...');
|
|
await apiRequest('/assessment/decision', 'POST', {
|
|
interviewId,
|
|
decision: 'Approved',
|
|
remarks: 'Cleared Level 1'
|
|
}, zmToken);
|
|
log(4, 'Level 1 Complete.');
|
|
await delay();
|
|
|
|
// 5. LEVEL-2 INTERVIEW
|
|
log(5, 'Scheduling Level 2 Interview...');
|
|
|
|
const intv2Response = await apiRequest('/assessment/interviews', 'POST', {
|
|
applicationId: applicationUUID,
|
|
level: 2,
|
|
scheduledAt: new Date(Date.now() + 172800000).toISOString(),
|
|
type: 'Online',
|
|
location: 'Teams',
|
|
participants: [ddLead.id, zbhUser.id]
|
|
}, leadToken);
|
|
const interviewId2 = intv2Response.data.id;
|
|
|
|
// log(5.1, 'DD-Lead Giving Feedback...');
|
|
// await apiRequest('/assessment/level2-feedback', 'POST', {
|
|
// interviewId: interviewId2,
|
|
// overallScore: 9.5,
|
|
// feedbackItems: [
|
|
// { type: 'Strategic Vision', comments: 'Excellent strategic planning.' },
|
|
// { type: 'Management Capabilities', comments: 'Strong team leadership.' },
|
|
// { type: 'Operational Understanding', comments: 'Knows the local market well.' }
|
|
// ],
|
|
// recommendation: 'Selected'
|
|
// }, leadToken);
|
|
|
|
// log(5.15, 'ZBH Giving Feedback...');
|
|
// const zbhToken = await login(zbhUser.email);
|
|
// await apiRequest('/assessment/level2-feedback', 'POST', {
|
|
// interviewId: interviewId2,
|
|
// overallScore: 9.0,
|
|
// feedbackItems: [
|
|
// { type: 'Strategic Vision', comments: 'Good alignment with brand.' },
|
|
// { type: 'Key Strengths', comments: 'Great location proposed.' },
|
|
// { type: 'Areas of Concern', comments: 'None at this time.' }
|
|
// ],
|
|
// recommendation: 'Selected'
|
|
// }, zbhToken);
|
|
|
|
// log(5.2, 'DD-Lead Finalizing Level 2 Decision...');
|
|
// await apiRequest('/assessment/decision', 'POST', {
|
|
// interviewId: interviewId2,
|
|
// decision: 'Approved',
|
|
// remarks: 'Cleared Level 2'
|
|
// }, leadToken);
|
|
// log(5, 'Level 2 Complete.');
|
|
// await delay();
|
|
|
|
// // 6. LEVEL-3 INTERVIEW
|
|
// log(6, 'Scheduling Level 3 Interview...');
|
|
// const headUser = users.data.find(u => u.email === EMAILS.DD_HEAD);
|
|
// const nbhUser = users.data.find(u => u.email === EMAILS.NBH);
|
|
|
|
// const intv3Response = await apiRequest('/assessment/interviews', 'POST', {
|
|
// applicationId: applicationUUID,
|
|
// level: 3,
|
|
// scheduledAt: new Date(Date.now() + 259200000).toISOString(),
|
|
// type: 'In-Person',
|
|
// location: 'HO',
|
|
// participants: [headUser.id, nbhUser.id]
|
|
// }, leadToken);
|
|
// const interviewId3 = intv3Response.data.id;
|
|
|
|
// log(6.1, 'NBH Giving Feedback...');
|
|
// const nbhToken = await login(EMAILS.NBH);
|
|
// await apiRequest('/assessment/level2-feedback', 'POST', {
|
|
// interviewId: interviewId3,
|
|
// overallScore: 10,
|
|
// feedbackItems: [
|
|
// { type: 'Business Vision & Strategy', comments: 'Highly recommended for this market.' },
|
|
// { type: 'Leadership & Decision Making', comments: 'Shows great potential.' }
|
|
// ],
|
|
// recommendation: 'Selected'
|
|
// }, nbhToken);
|
|
|
|
// log(6.15, 'DD-Head Giving Feedback...');
|
|
// const headToken = await login(EMAILS.DD_HEAD);
|
|
// await apiRequest('/assessment/level2-feedback', 'POST', {
|
|
// interviewId: interviewId3,
|
|
// overallScore: 9.5,
|
|
// feedbackItems: [
|
|
// { type: 'Operational & Financial Readiness', comments: 'Financially sound.' },
|
|
// { type: 'Brand Alignment', comments: 'Understands Royal Enfield ethos perfectly.' }
|
|
// ],
|
|
// recommendation: 'Selected'
|
|
// }, headToken);
|
|
|
|
// log(6.2, 'Head Finalizing Level 3 Decision...');
|
|
// await apiRequest('/assessment/decision', 'POST', {
|
|
// interviewId: interviewId3,
|
|
// decision: 'Approved',
|
|
// remarks: 'Cleared Level 3. Moving to FDD.'
|
|
// }, headToken);
|
|
// log(6, 'Level 3 Complete. Stage is now FDD Verification.');
|
|
// await delay();
|
|
|
|
// // 6.3 FDD ASSIGNMENT
|
|
// log(6.3, 'Admin Assigning Application to FDD Agency...');
|
|
// const fddUser = users.data.find(u => u.email === EMAILS.FDD);
|
|
// await apiRequest('/fdd/assign', 'POST', {
|
|
// applicationId: applicationUUID,
|
|
// assignedToAgency: fddUser.id
|
|
// }, adminToken);
|
|
// log(6.3, 'FDD Agency assigned successfully.');
|
|
// await delay();
|
|
|
|
// // 7. FDD MILESTONE
|
|
// log(7, 'FDD Agency Discovery & Report Upload...');
|
|
// const fddToken = await login(EMAILS.FDD);
|
|
|
|
// // FETCH ASSIGNMENT ID
|
|
// const assignmentRes = await apiRequest(`/fdd/${applicationUUID}`, 'GET', null, fddToken);
|
|
// const assignmentId = assignmentRes.data.id;
|
|
// log(7, `Found Assignment ID: ${assignmentId}`);
|
|
|
|
// await apiRequest('/fdd/report', 'POST', {
|
|
// assignmentId,
|
|
// findings: 'Finance records clean.',
|
|
// recommendation: 'Approved'
|
|
// }, fddToken);
|
|
|
|
// log(7.1, 'Admin Approving FDD Final Stage...');
|
|
// await apiRequest('/assessment/stage-decision', 'POST', {
|
|
// applicationId: applicationUUID,
|
|
// stageCode: 'FDD_VERIFICATION',
|
|
// decision: 'Approved',
|
|
// remarks: 'FDD documents verified.'
|
|
// }, adminToken);
|
|
// log(7, 'FDD Milestone Complete.');
|
|
// await delay();
|
|
|
|
// log(7.4, 'Uploading mandatory documents prior to LOI generation...');
|
|
// const requiredDocs = ['CIBIL Report', 'Proposed Site City Map', 'Bank Statement', 'GST Certificate', 'PAN Card'];
|
|
// for (const doc of requiredDocs) {
|
|
// await mockUploadDocument(applicationUUID, adminToken, doc);
|
|
// }
|
|
// await delay(1000);
|
|
|
|
// // 7.5 LOI APPROVAL
|
|
// log(7.5, 'LOI Generation & Approval...');
|
|
// const loiRes = await apiRequest('/loi/request', 'POST', { applicationId: applicationUUID }, adminToken);
|
|
// const loiRequestId = loiRes.data.id;
|
|
|
|
// // Head Approval
|
|
// await apiRequest(`/loi/request/${loiRequestId}/approve`, 'POST', {
|
|
// action: 'Approved',
|
|
// remarks: 'Head Authorization for LOI'
|
|
// }, headToken);
|
|
|
|
// // NBH Approval
|
|
// await apiRequest(`/loi/request/${loiRequestId}/approve`, 'POST', {
|
|
// action: 'Approved',
|
|
// remarks: 'NBH Authorization for LOI'
|
|
// }, nbhToken);
|
|
|
|
// log(7.5, 'LOI Milestone Complete.');
|
|
// await delay();
|
|
|
|
// // 8. PAYMENT GATE (SECURITY DEPOSIT FIRST AS PER CURRENT FLOW)
|
|
// log(8, 'Finance Verifying SECURITY_DEPOSIT to unlock LOI Issued...');
|
|
// const financeToken = await login(EMAILS.FINANCE);
|
|
// await apiRequest('/loa/security-deposit', 'POST', {
|
|
// applicationId: applicationUUID,
|
|
// amount: 500000,
|
|
// paymentReference: 'PAY-888999',
|
|
// depositType: 'SECURITY_DEPOSIT',
|
|
// status: 'Verified'
|
|
// }, financeToken);
|
|
// log(8, 'Security Deposit Verified.')
|
|
// // 9. GENERATE DEALER CODES (align with backend gate: LOI Issued required)
|
|
// let statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);
|
|
// log(9, `Current status before code generation: ${statusBeforeCodeGen}`);
|
|
// log(9, 'Ensuring mandatory PAN/GST/Bank fields before code generation...');
|
|
// 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...');
|
|
// await apiRequest('/loa/security-deposit', 'POST', {
|
|
// applicationId: applicationUUID,
|
|
// amount: 500000,
|
|
// paymentReference: `PAY-RETRY-${Date.now()}`,
|
|
// depositType: 'SECURITY_DEPOSIT',
|
|
// status: 'Verified'
|
|
// }, financeToken);
|
|
// await delay();
|
|
// statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);
|
|
// 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...');
|
|
// await apiRequest(`/onboarding/applications/${applicationUUID}/status`, 'PUT', {
|
|
// status: 'LOI Issued',
|
|
// stage: 'LOI',
|
|
// reason: 'E2E script alignment: unlock dealer code generation after Security Details checks.'
|
|
// }, adminToken);
|
|
// await delay();
|
|
// statusBeforeCodeGen = await getApplicationStatus(applicationUUID, adminToken);
|
|
// log(9, `Status after admin transition: ${statusBeforeCodeGen}`);
|
|
// }
|
|
|
|
// if (statusBeforeCodeGen !== 'LOI Issued' && statusBeforeCodeGen !== 'Dealer Code Generation') {
|
|
// throw new Error(`Cannot generate codes: expected LOI Issued/Dealer Code Generation, got ${statusBeforeCodeGen}`);
|
|
// }
|
|
|
|
// log(9, 'Admin Generating SAP Dealer Codes...');
|
|
// await apiRequest(`/onboarding/applications/${applicationUUID}/generate-codes`, 'POST', {}, adminToken);
|
|
// log(9, 'Dealer Codes Generated.');
|
|
// await delay();
|
|
|
|
// // 10. FIRST FILL (POST CODE-GENERATION)
|
|
// log(10, 'Finance Verifying FIRST FILL (₹15L)...');
|
|
// await apiRequest('/loa/security-deposit', 'POST', {
|
|
// applicationId: applicationUUID,
|
|
// amount: 1500000,
|
|
// paymentReference: 'PAY-FIN-999',
|
|
// depositType: 'FIRST_FILL',
|
|
// status: 'Verified'
|
|
// }, financeToken);
|
|
// log(10, 'Final Security Deposit Verified.');
|
|
// await delay();
|
|
|
|
// // 11. ADMIN UPDATING STATUTORY & BANK DETAILS
|
|
// log(11, 'Admin Updating Statutory & Bank Details for LOA Approval Gate...');
|
|
// await apiRequest(`/onboarding/applications/${applicationUUID}`, 'PUT', {
|
|
// accountHolderName: 'Ramesh Automobiles Private Limited',
|
|
// panNumber: 'ABCDE1234F',
|
|
// gstNumber: '07ABCDE1234F1Z5',
|
|
// bankName: 'HDFC Bank',
|
|
// accountNumber: '50100223344556',
|
|
// ifscCode: 'HDFC0001234'
|
|
// }, adminToken);
|
|
// log(11, 'Statutory & Bank details updated.');
|
|
// await delay();
|
|
|
|
// // 12. FINAL LOA APPROVAL
|
|
// log(12, 'NBH & Head Approving Final LOA...');
|
|
// const loaRes = await apiRequest('/loa/request', 'POST', { applicationId: applicationUUID }, headToken);
|
|
// const finalLoaRequestId = loaRes.data.id;
|
|
|
|
// await apiRequest(`/loa/request/${finalLoaRequestId}/approve`, 'POST', {
|
|
// action: 'Approved',
|
|
// remarks: 'Head Authorization (Level 1)'
|
|
// }, headToken);
|
|
|
|
// await apiRequest(`/loa/request/${finalLoaRequestId}/approve`, 'POST', {
|
|
// action: 'Approved',
|
|
// remarks: 'NBH Approval (Level 2)'
|
|
// }, nbhToken);
|
|
// log(12, 'LOA Fully Approved.');
|
|
// await delay();
|
|
|
|
// // 13. EOR (EVIDENCE OF READINESS) CHECKLIST VERIFICATION
|
|
// log(13, 'Admin Initializing EOR Checklist (100% Readiness Requirement)...');
|
|
// const eorInit = await apiRequest('/eor', 'POST', { applicationId: applicationUUID }, adminToken);
|
|
// const checklistId = eorInit.data.id;
|
|
// log(13, `EOR Checklist Created (ID: ${checklistId})`);
|
|
|
|
// log(13.1, 'Auditor Verifying all 12 mandatory EOR items as COMPLIANT...');
|
|
// const eorItems = [
|
|
// { itemType: 'Sales', description: 'Sales Standards' },
|
|
// { itemType: 'Service', description: 'Service & Spares' },
|
|
// { itemType: 'IT', description: 'DMS infra' },
|
|
// { itemType: 'Training', description: 'Manpower Training' },
|
|
// { itemType: 'Statutory', description: 'Trade certificate with test ride bikes registration' },
|
|
// { itemType: 'Statutory', description: 'GST certificate including Accessories & Apparels billing' },
|
|
// { itemType: 'Finance', description: 'Inventory Funding' },
|
|
// { itemType: 'IT', description: 'Virtual code availability' },
|
|
// { itemType: 'Finance', description: 'Vendor payments' },
|
|
// { itemType: 'Marketing', description: 'Details for website submission' },
|
|
// { itemType: 'Insurance', description: 'Infra Insurance both Showroom and Service center' },
|
|
// { itemType: 'IT', description: 'Auto ordering' }
|
|
// ];
|
|
|
|
// for (const item of eorItems) {
|
|
// process.stdout.write(`.`); // Visual progress
|
|
// await apiRequest(`/eor/item/${checklistId}`, 'POST', {
|
|
// ...item,
|
|
// isCompliant: true,
|
|
// remarks: 'Verified by Auditor - Compliant'
|
|
// }, adminToken);
|
|
// }
|
|
// console.log('\n[STEP 13.1] All EOR items marked as compliant.');
|
|
|
|
// log(13.2, 'Auditor Submitting Final EOR Audit...');
|
|
// await apiRequest(`/eor/audit/${checklistId}`, 'POST', {
|
|
// status: 'Completed',
|
|
// overallComments: 'Dealer is 100% ready for inauguration. All infra and statutory items verified.'
|
|
// }, adminToken);
|
|
|
|
// // Status check
|
|
// const finalAppStatus = await apiRequest(`/onboarding/applications/${applicationUUID}`, 'GET', null, adminToken);
|
|
// log(13.2, `Application Status after EOR: ${finalAppStatus.data.overallStatus}`);
|
|
// await delay();
|
|
|
|
// // 14. FINAL ONBOARDING
|
|
// log(14, 'Admin Finalizing Dealer Onboarding...');
|
|
// await apiRequest('/dealers', 'POST', { applicationId: applicationUUID }, adminToken);
|
|
// await delay();
|
|
|
|
// // 15. VERIFICATION
|
|
// log(15, 'Verifying Dealer Record Creation...');
|
|
// const dealerRes = await apiRequest(`/dealers/application/${applicationUUID}`, 'GET', null, adminToken);
|
|
// if (!dealerRes.success || !dealerRes.data) {
|
|
// throw new Error('Verification Failed: Dealer record not found after onboarding.');
|
|
// }
|
|
// log(15, `Dealer Found: ${dealerRes.data.legalName} (${dealerRes.data.id})`);
|
|
|
|
// log(15.1, 'Verifying User Account Role Update...');
|
|
// const userRes = await apiRequest(`/admin/users`, 'GET', null, adminToken);
|
|
// const dealerUser = userRes.data.find(u => u.email === PROSPECT_EMAIL);
|
|
// if (!dealerUser || dealerUser.roleCode !== 'Dealer') {
|
|
// 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.2, '--- WORKFLOW COMPLETED SUCCESSFULLY! ---');
|
|
// log(15.2, `The application ${applicationId} is now at 'ONBOARDED' status and Dealer profile is active.`);
|
|
}
|
|
|
|
/**
|
|
* START
|
|
*/
|
|
triggerWorkflow().catch(err => {
|
|
console.error('\x1b[31mCRITICAL FAILURE during workflow execution:\x1b[0m');
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|