/** * ROYAL ENFIELD DEALER ONBOARDING - END-TO-END WORKFLOW TRIGGER * This script automates the entire journey from Application to LOA. */ const BASE_URL = 'http://localhost:5000/api'; const PASSWORD = 'Admin@123'; const OTP = '123456'; // 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: 'rbm.ncr@royalenfield.com', ZM_L1: 'zm.ncr@royalenfield.com', DD_LEAD: 'ddlead@royalenfield.com', NBH: 'nbh@royalenfield.com', DD_HEAD: 'ddhead@royalenfield.com', FDD: 'fdd@royalenfield.com', FINANCE: 'finance@royalenfield.com', DD_ADMIN: 'lince@gmail.com', ASM: 'asm.sdelhi@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." }; // State to store IDs between steps let applicationId = null; let applicationUUID = null; let interviewId = null; let loaRequestId = null; /** * HELPERS */ const delay = (ms = 5000) => 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) { const data = await apiRequest('/auth/login', 'POST', { email, password: PASSWORD }); return data.token; // 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 } /** * MAIN WORKFLOW */ async function triggerWorkflow() { console.log('--- STARTING DEALER ONBOARDING E2E FLOW ---\n'); // 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 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/interviews/${interviewId}/evaluation`, 'POST', { ktScore: 85, feedback: 'Strong business acumen.', recommendation: 'Selected', status: 'Completed' }, rbmToken); // FEEDBACK ZM log(4.2, 'ZM Giving Feedback...'); const zmToken = await login(EMAILS.ZM_L1); await apiRequest(`/assessment/interviews/${interviewId}/evaluation`, 'POST', { ktScore: 90, feedback: 'Good vision for RE brand.', recommendation: 'Selected', status: 'Completed' }, 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] }, leadToken); const interviewId2 = intv2Response.data.id; log(5.1, 'DD-Lead Giving Feedback...'); await apiRequest(`/assessment/interviews/${interviewId2}/evaluation`, 'POST', { ktScore: 95, feedback: 'Excellent profile.', recommendation: 'Selected', status: 'Completed' }, leadToken); 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/interviews/${interviewId3}/evaluation`, 'POST', { ktScore: 100, feedback: 'Highly recommended.', recommendation: 'Selected', status: 'Completed' }, nbhToken); log(6.2, 'Head Finalizing Level 3 Decision...'); const headToken = await login(EMAILS.DD_HEAD); 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(); // 8. PAYMENT GATE log(8, 'Prospect Uploading Payment Receipt (Mock)...'); // In real use, this is a multipart upload. Here we simulate the record update. const financeToken = await login(EMAILS.FINANCE); await apiRequest('/loa/security-deposit', 'POST', { applicationId: applicationUUID, amount: 500000, paymentReference: 'PAY-888999', depositType: 'INITIAL', status: 'Verified' }, financeToken); log(8, 'Initial Security Deposit Verified.'); log(8.1, 'Finance Verifying FINAL Security Deposit (₹15L)...'); await apiRequest('/loa/security-deposit', 'POST', { applicationId: applicationUUID, amount: 1500000, paymentReference: 'PAY-FIN-999', depositType: 'FINAL', status: 'Verified' }, financeToken); log(8.1, 'Final Security Deposit Verified.'); await delay(); // 9. FINAL LOA APPROVAL log(9, 'NBH & Head Approving Final LOA...'); // Trigger LOA Request const loaRes = await apiRequest('/loa/request', 'POST', { applicationId: applicationUUID }, headToken); loaRequestId = loaRes.data.id; await apiRequest(`/loa/request/${loaRequestId}/approve`, 'POST', { action: 'Approved', remarks: 'Head Authorization (Level 1)' }, headToken); await apiRequest(`/loa/request/${loaRequestId}/approve`, 'POST', { action: 'Approved', remarks: 'NBH Approval (Level 2)' }, nbhToken); log(9, '--- WORKFLOW COMPLETED SUCCESSFULLY! ---'); log(9, `The application ${applicationId} is now at 'EOR Work' stage.`); } /** * START */ triggerWorkflow().catch(err => { console.error('\x1b[31mCRITICAL FAILURE during workflow execution:\x1b[0m'); console.error(err); process.exit(1); });