From 7fbf134cf1e40eefbae7830c01fd815f4d63d5f7 Mon Sep 17 00:00:00 2001 From: laxman h Date: Thu, 16 Apr 2026 17:44:14 +0530 Subject: [PATCH] tab filters in differnt module changes and amount update from F&F fixed checking for the dues update from two placeds finance & normal departmental response need to finalisre one --- .../self-service/resignation.controller.ts | 99 +++-- .../settlement/settlement.controller.ts | 56 ++- src/services/ResignationWorkflowService.ts | 8 +- trigger-workflow.js | 390 +++++++++--------- 4 files changed, 307 insertions(+), 246 deletions(-) diff --git a/src/modules/self-service/resignation.controller.ts b/src/modules/self-service/resignation.controller.ts index 1b80b4e..0cad428 100644 --- a/src/modules/self-service/resignation.controller.ts +++ b/src/modules/self-service/resignation.controller.ts @@ -310,7 +310,9 @@ export const approveResignation = async (req: AuthRequest, res: Response, next: [RESIGNATION_STAGES.DD_LEAD]: RESIGNATION_STAGES.NBH, [RESIGNATION_STAGES.NBH]: RESIGNATION_STAGES.DD_ADMIN, [RESIGNATION_STAGES.DD_ADMIN]: RESIGNATION_STAGES.LEGAL, - [RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.FNF_INITIATED, + // Legal approval should complete only the Legal stage. + // F&F initiation is explicitly triggered via `pushfnf` action (with LWD/force gates). + [RESIGNATION_STAGES.LEGAL]: RESIGNATION_STAGES.LEGAL, [RESIGNATION_STAGES.FNF_INITIATED]: RESIGNATION_STAGES.COMPLETED }; @@ -320,6 +322,22 @@ export const approveResignation = async (req: AuthRequest, res: Response, next: return res.status(400).json({ success: false, message: 'Cannot move to next stage from current state' }); } + // Guard before transition: F&F initiation is allowed only on/after LWD unless forced. + if (nextStage === RESIGNATION_STAGES.FNF_INITIATED) { + const today = new Date(); + const lwd = resignation.lastOperationalDateServices || resignation.lastOperationalDateSales; + const { force } = req.body; + + if (!force && lwd && today < new Date(lwd)) { + await transaction.rollback(); + return res.status(400).json({ + success: false, + message: `F&F can only be initiated on or after the Last Working Day (${lwd}).`, + canForce: true + }); + } + } + // Sequence guard: resignation can be marked completed only after F&F settlement is complete. if ( resignation.currentStage === RESIGNATION_STAGES.FNF_INITIATED && @@ -340,7 +358,8 @@ export const approveResignation = async (req: AuthRequest, res: Response, next: // Transition via Workflow Service await ResignationWorkflowService.transitionResignation(resignation, nextStage, req.user.id, { remarks, - status: getResignationStatusForStage(nextStage) + status: getResignationStatusForStage(nextStage), + transaction }); // Special logic for F&F and Completion @@ -351,47 +370,37 @@ export const approveResignation = async (req: AuthRequest, res: Response, next: } if (nextStage === RESIGNATION_STAGES.FNF_INITIATED) { - const today = new Date(); - const lwd = resignation.lastOperationalDateServices || resignation.lastOperationalDateSales; - const { force } = req.body; - - if (!force && lwd && today < new Date(lwd)) { - await transaction.rollback(); - return res.status(400).json({ - success: false, - message: `F&F can only be initiated on or after the Last Working Day (${lwd}).`, - canForce: true - }); + const existingFnF = await db.FnF.findOne({ where: { resignationId: resignation.id }, transaction }); + if (!existingFnF) { + const sapDues = await ExternalMocksService.mockGetFinancialDuesFromSap((resignation as any).outlet.code); + const dealerProfileId = (resignation as any).dealer?.dealerId; + + const fnf = await db.FnF.create({ + settlementId: NomenclatureService.generateFnFId(), + resignationId: resignation.id, + outletId: resignation.outletId, + dealerId: dealerProfileId, // Correctly using the Dealer model ID + status: 'Initiated', + totalReceivables: sapDues.data.outstandingInvoices, + totalPayables: sapDues.data.securityDeposit, + netAmount: sapDues.data.securityDeposit - sapDues.data.outstandingInvoices + }, { transaction }); + + await db.FnFLineItem.bulkCreate([ + { fnfId: fnf.id, itemType: 'Receivable', description: 'Outstanding Invoices from SAP', department: 'Finance', amount: sapDues.data.outstandingInvoices, addedBy: req.user.id }, + { fnfId: fnf.id, itemType: 'Payable', description: 'Security Deposit from SAP', department: 'Finance', amount: sapDues.data.securityDeposit, addedBy: req.user.id } + ], { transaction }); + + const { FNF_DEPARTMENTS } = await import('../../common/config/constants.js'); + await db.FffClearance.bulkCreate( + FNF_DEPARTMENTS.map(dept => ({ + fnfId: fnf.id, + department: dept, + status: 'Pending' + })), + { transaction } + ); } - - const sapDues = await ExternalMocksService.mockGetFinancialDuesFromSap((resignation as any).outlet.code); - const dealerProfileId = (resignation as any).dealer?.dealerId; - - const fnf = await db.FnF.create({ - settlementId: NomenclatureService.generateFnFId(), - resignationId: resignation.id, - outletId: resignation.outletId, - dealerId: dealerProfileId, // Correctly using the Dealer model ID - status: 'Initiated', - totalReceivables: sapDues.data.outstandingInvoices, - totalPayables: sapDues.data.securityDeposit, - netAmount: sapDues.data.securityDeposit - sapDues.data.outstandingInvoices - }, { transaction }); - - await db.FnFLineItem.bulkCreate([ - { fnfId: fnf.id, itemType: 'Receivable', description: 'Outstanding Invoices from SAP', department: 'Finance', amount: sapDues.data.outstandingInvoices, addedBy: req.user.id }, - { fnfId: fnf.id, itemType: 'Payable', description: 'Security Deposit from SAP', department: 'Finance', amount: sapDues.data.securityDeposit, addedBy: req.user.id } - ], { transaction }); - - const { FNF_DEPARTMENTS } = await import('../../common/config/constants.js'); - await db.FffClearance.bulkCreate( - FNF_DEPARTMENTS.map(dept => ({ - fnfId: fnf.id, - department: dept, - status: 'Pending' - })), - { transaction } - ); } await transaction.commit(); @@ -409,7 +418,11 @@ export const approveResignation = async (req: AuthRequest, res: Response, next: logger.error('[resignation] workflow worknote (approve):', wnErr); } - res.json({ success: true, message: 'Resignation approved successfully', nextStage, resignation }); + const message = (sourceStage === RESIGNATION_STAGES.LEGAL && nextStage === RESIGNATION_STAGES.LEGAL) + ? 'Legal stage approved successfully. Use Push to F&F to initiate settlement as per LWD rules.' + : 'Resignation approved successfully'; + + res.json({ success: true, message, nextStage, resignation }); } catch (error) { if (transaction) await transaction.rollback(); logger.error('Error approving resignation:', error); diff --git a/src/modules/settlement/settlement.controller.ts b/src/modules/settlement/settlement.controller.ts index d2e43b2..dcdb7a6 100644 --- a/src/modules/settlement/settlement.controller.ts +++ b/src/modules/settlement/settlement.controller.ts @@ -385,13 +385,51 @@ export const updateClearance = async (req: AuthRequest, res: Response) => { try { const { id, clearanceId } = req.params; const body = (req.body || {}) as Record; - const { status, remarks, documentId, supportingDocument } = body; + const { status, remarks, documentId, supportingDocument, amount, type } = body; const clearance = await FffClearance.findOne({ where: { id: clearanceId, fnfId: id } }); if (!clearance) return res.status(404).json({ success: false, message: 'Clearance record not found' }); const uploadedSupportingDocument = req.file ? `/uploads/documents/${req.file.filename}` : undefined; + const enteredAmount = Math.abs(Number(amount) || 0); + const clearanceType = String(type || '').toLowerCase(); + const itemType = clearanceType === 'payable' + ? 'Payable' + : clearanceType === 'deduction' + ? 'Deduction' + : 'Receivable'; + const syntheticDescription = 'Department Clearance - Manual Update'; - const normalizedStatus = normalizeClearanceStatus(status || clearance.status, Number(clearance.amount || 0)); + // Persist amount/type as F&F line item so UI totals and department amount reflect user input. + const existingSyntheticLine = await FnFLineItem.findOne({ + where: { + fnfId: id, + department: clearance.department, + description: syntheticDescription + } + }); + + if (enteredAmount > 0) { + if (existingSyntheticLine) { + await existingSyntheticLine.update({ + itemType, + amount: enteredAmount, + addedBy: req.user?.id || existingSyntheticLine.addedBy + }); + } else { + await FnFLineItem.create({ + fnfId: id, + itemType, + description: syntheticDescription, + department: clearance.department, + amount: enteredAmount, + addedBy: req.user?.id || null + }); + } + } else if (existingSyntheticLine) { + await existingSyntheticLine.destroy(); + } + + const normalizedStatus = normalizeClearanceStatus(status || clearance.status, enteredAmount); await clearance.update({ status: normalizedStatus, remarks: remarks || clearance.remarks, @@ -413,7 +451,12 @@ export const updateClearance = async (req: AuthRequest, res: Response) => { fnfId: id, action: 'CLEARANCE_UPDATED', remarks: remarks || 'No remarks', - details: { department: clearance.department, status: normalizedStatus } + details: { + department: clearance.department, + status: normalizedStatus, + amount: enteredAmount, + type: itemType + } }); } catch (auditError) { console.error('[SettlementController] Local FnFAudit creation failed:', auditError); @@ -433,7 +476,12 @@ export const updateClearance = async (req: AuthRequest, res: Response) => { [parentKey]: parentId, action: 'STAKEHOLDER_CLEARANCE_UPDATED', remarks: `Automated sync from F&F: ${remarks || 'No remarks'}`, - details: { department: clearance.department, status: normalizedStatus } + details: { + department: clearance.department, + status: normalizedStatus, + amount: enteredAmount, + type: itemType + } }); } catch (parentAuditError) { console.error('[SettlementController] Parent Audit creation failed:', parentAuditError); diff --git a/src/services/ResignationWorkflowService.ts b/src/services/ResignationWorkflowService.ts index 8f90c2f..c3904f7 100644 --- a/src/services/ResignationWorkflowService.ts +++ b/src/services/ResignationWorkflowService.ts @@ -12,7 +12,7 @@ export class ResignationWorkflowService { * Standardized method to transition a resignation request status */ static async transitionResignation(resignation: any, targetStage: string, userId: string | null = null, metadata: any = {}) { - const { action, remarks, status } = metadata; + const { action, remarks, status, transaction } = metadata; const sourceStage = resignation.currentStage; const updateData: any = { @@ -38,7 +38,7 @@ export class ResignationWorkflowService { await resignation.update({ ...updateData, timeline: updatedTimeline - }); + }, transaction ? { transaction } : undefined); // 3. Create Audit Log let auditAction: any = AUDIT_ACTIONS.APPROVED; @@ -52,7 +52,7 @@ export class ResignationWorkflowService { action: auditAction, remarks: remarks || '', details: { status: updateData.status, stage: sourceStage, targetStage: targetStage } - }); + }, transaction ? { transaction } : undefined); console.log(`[ResignationWorkflowService] Transitioned Resignation ${resignation.resignationId} to ${targetStage}`); @@ -85,7 +85,7 @@ export class ResignationWorkflowService { await user.update({ status: 'deactivated', isActive: false - }); + }, transaction ? { transaction } : undefined); } } else { logger.warn(`[ResignationWorkflowService] No user account found with dealerId ${resignation.dealerId}`); diff --git a/trigger-workflow.js b/trigger-workflow.js index 7dbac93..c0e1da2 100644 --- a/trigger-workflow.js +++ b/trigger-workflow.js @@ -347,229 +347,229 @@ async function triggerWorkflow() { 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(); + 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); + // 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}`); + // 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); + 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.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); + 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; + // 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); + // 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); + // 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(); + 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); + // 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}`); - // } + 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}`); - // } + // 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}`); - // } + 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(); + 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(); + // 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(); + // 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; + // 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: '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(); + 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})`); + // 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' } - // ]; + 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.'); + 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); + 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(); + // 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(); + // 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})`); + // 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.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.`); + log(15.2, '--- WORKFLOW COMPLETED SUCCESSFULLY! ---'); + log(15.2, `The application ${applicationId} is now at 'ONBOARDED' status and Dealer profile is active.`); } /**