/** * Seed demo data: Form 16 submissions and other workflow requests. * Data is inserted into database tables only (no hardcoded data in app code). * * Prerequisites: * - Run seed:admin-user (for admin user) * - Run seed:dealer-user (for dealer user + dealer record for Form 16) * * Usage: npm run seed:demo-requests */ import { Op } from 'sequelize'; import { sequelize } from '../config/database'; import { User, WorkflowRequest, Form16aSubmission, Form16CreditNote, Activity, Document, Dealer, } from '../models'; import { Priority, WorkflowStatus } from '../types/common.types'; import { generateRequestNumber } from '../utils/helpers'; import logger from '../utils/logger'; const DEMO_MARKER_TITLE_PREFIX = 'Form 16A - 2024-25'; // Used to detect existing demo Form 16 data const DEMO_CUSTOM_TITLE = '[Demo] Sample workflow request'; async function getOrResolveUsers(): Promise<{ adminUser: User | null; dealerUser: User | null; dealerCode: string | null }> { const adminUser = await User.findOne({ where: { email: 'admin@example.com' } }); const dealerUser = await User.findOne({ where: { email: 'testreflow@example.com' } }); let dealerCode: string | null = null; if (dealerUser) { const dealer = await Dealer.findOne({ where: { dealerPrincipalEmailId: 'testreflow@example.com', isActive: true }, attributes: ['salesCode', 'dlrcode'], }); dealerCode = dealer?.salesCode ?? dealer?.dlrcode ?? null; } return { adminUser, dealerUser, dealerCode }; } async function hasExistingDemoForm16(): Promise { const count = await WorkflowRequest.count({ where: { templateType: 'FORM_16', title: { [Op.like]: `${DEMO_MARKER_TITLE_PREFIX}%` }, }, }); return count >= 2; } /** Demo dealers used for "non-submitted dealers" list: active dealers with no Form 16 submission for the demo FY/quarter. */ const DEMO_NON_SUBMITTED_DEALERS = [ { dlrcode: 'DEMO-NOSUB-001', dealership: 'Demo Motors Mumbai', dealerPrincipalName: 'Demo Mumbai', dealerPrincipalEmailId: 'demo.nosub.1@example.com', state: 'Maharashtra', city: 'Mumbai' }, { dlrcode: 'DEMO-NOSUB-002', dealership: 'Demo Enfield Delhi', dealerPrincipalName: 'Demo Delhi', dealerPrincipalEmailId: 'demo.nosub.2@example.com', state: 'Delhi', city: 'New Delhi' }, { dlrcode: 'DEMO-NOSUB-003', dealership: 'Demo Royal Bangalore', dealerPrincipalName: 'Demo Bangalore', dealerPrincipalEmailId: 'demo.nosub.3@example.com', state: 'Karnataka', city: 'Bengaluru' }, ]; async function ensureDemoNonSubmittedDealers(): Promise { for (const data of DEMO_NON_SUBMITTED_DEALERS) { const [dealer] = await Dealer.findOrCreate({ where: { dlrcode: data.dlrcode }, defaults: { ...data, salesCode: data.dlrcode, isActive: true, } as any, }); if (dealer && !dealer.isActive) { await dealer.update({ isActive: true }); } } logger.info('[Seed Demo] Demo non-submitted dealers ensured (they have no Form 16 submissions for 2024-25).'); } async function seedDemoRequests(): Promise { // Always ensure demo dealers exist first (for both submission and non-submitted lists). // These dealers are in the dealers table; only the test dealer gets Form 16 submissions below. await ensureDemoNonSubmittedDealers(); const { adminUser, dealerUser, dealerCode } = await getOrResolveUsers(); const initiatorId = adminUser?.userId ?? dealerUser?.userId; if (!initiatorId) { logger.warn('[Seed Demo] No admin or dealer user found. Run seed:admin-user and seed:dealer-user first.'); return; } if (await hasExistingDemoForm16()) { logger.info('[Seed Demo] Demo Form 16 requests already present. Skipping to avoid duplicates.'); return; } const now = new Date(); // ---- 1) Create a few CUSTOM (non–Form 16) requests so "other requests" are visible ---- for (let i = 1; i <= 2; i++) { const requestNumber = await generateRequestNumber(); await WorkflowRequest.create({ requestNumber, initiatorId, templateType: 'CUSTOM', workflowType: 'NON_TEMPLATIZED', title: `${DEMO_CUSTOM_TITLE} ${i}`, description: `Demo workflow request for testing. Created by seed script.`, priority: Priority.STANDARD, status: i === 1 ? WorkflowStatus.PENDING : WorkflowStatus.PENDING, currentLevel: 1, totalLevels: 1, totalTatHours: 48, submissionDate: now, isDraft: false, isDeleted: false, isPaused: false, }); } // ---- 2) Create Form 16 requests + submissions (and optional credit notes / activity / docs) ---- if (!dealerUser || !dealerCode) { logger.warn('[Seed Demo] Dealer user or dealer code missing. Form 16 demo requests skipped. Run seed:dealer-user.'); } else { const form16InitiatorId = dealerUser.userId; const form16Demos = [ { fy: '2024-25', quarter: 'Q1', deductor: 'Royal Enfield Motors Ltd', tds: 15000, total: 150000, cnAmount: 15000, withCreditNote: true, withdrawn: false }, { fy: '2024-25', quarter: 'Q2', deductor: 'Royal Enfield Motors Ltd', tds: 18000, total: 180000, cnAmount: 18000, withCreditNote: true, withdrawn: true }, { fy: '2024-25', quarter: 'Q3', deductor: 'Royal Enfield Motors Ltd', tds: 12000, total: 120000, cnAmount: null, withCreditNote: false, withdrawn: false }, ]; for (const demo of form16Demos) { const requestNumber = await generateRequestNumber(); const title = `Form 16A - ${demo.fy} ${demo.quarter}`; const description = `Form 16A TDS certificate submission. Deductor: ${demo.deductor}.`; const workflow = await WorkflowRequest.create({ requestNumber, initiatorId: form16InitiatorId, templateType: 'FORM_16', workflowType: 'FORM_16', title, description, priority: Priority.STANDARD, status: demo.withCreditNote && !demo.withdrawn ? WorkflowStatus.CLOSED : WorkflowStatus.PENDING, currentLevel: 1, totalLevels: 1, totalTatHours: 0, submissionDate: now, closureDate: demo.withCreditNote && !demo.withdrawn ? now : undefined, isDraft: false, isDeleted: false, isPaused: false, }); const requestId = (workflow as any).requestId; const form16aNumber = `DEMO-F16-${demo.quarter}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; const submission = await Form16aSubmission.create({ requestId, dealerCode, form16aNumber, financialYear: demo.fy, quarter: demo.quarter, version: 1, tdsAmount: demo.tds, totalAmount: demo.total, tanNumber: 'BLRE00001E', deductorName: demo.deductor, documentUrl: 'https://example.com/demo-form16a.pdf', status: 'pending', submittedDate: now, }); // Activity: dealer submitted Form 16 await Activity.create({ requestId, userId: form16InitiatorId, userName: (dealerUser as any).displayName || (dealerUser as any).firstName + ' ' + (dealerUser as any).lastName || 'Dealer', activityType: 'FORM_16_SUBMITTED', activityDescription: `Dealer submitted Form 16A for ${demo.fy} ${demo.quarter}. Certificate: ${form16aNumber}.`, activityCategory: 'submission', isSystemEvent: false, }); // Document: attached Form 16 (placeholder so Docs tab shows an entry) await Document.create({ requestId, uploadedBy: form16InitiatorId, fileName: `form16a-${demo.quarter}.pdf`, originalFileName: `Form16A_${demo.fy}_${demo.quarter}.pdf`, fileType: 'application/pdf', fileExtension: 'pdf', fileSize: 1024, filePath: `form16-demo/${requestId}/form16a.pdf`, mimeType: 'application/pdf', checksum: 'demo-checksum-' + requestId.slice(0, 8), isGoogleDoc: false, category: 'SUPPORTING', version: 1, isDeleted: false, downloadCount: 0, uploadedAt: now, }); if (demo.withCreditNote && demo.cnAmount != null) { const creditNote = await Form16CreditNote.create({ submissionId: submission.id, creditNoteNumber: `DEMO-CN-${demo.quarter}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, sapDocumentNumber: `SAP-${demo.quarter}-DEMO`, amount: demo.cnAmount, issueDate: now.toISOString().slice(0, 10) as unknown as Date, financialYear: demo.fy, quarter: demo.quarter, status: demo.withdrawn ? 'withdrawn' : 'issued', issuedBy: adminUser?.userId, createdAt: now, updatedAt: now, }); await Activity.create({ requestId, userId: adminUser?.userId ?? undefined, userName: 'RE Admin', activityType: demo.withdrawn ? 'CREDIT_NOTE_WITHDRAWN' : 'CREDIT_NOTE_ISSUED', activityDescription: demo.withdrawn ? `Credit note ${creditNote.creditNoteNumber} was withdrawn by RE user.` : `Credit note ${creditNote.creditNoteNumber} generated for ${demo.fy} ${demo.quarter}.`, activityCategory: 'workflow', isSystemEvent: false, }); } } } logger.info('[Seed Demo] Demo requests, Form 16 submissions, and non-submitted dealers demo data created successfully.'); } if (require.main === module) { sequelize .authenticate() .then(() => seedDemoRequests()) .then(() => process.exit(0)) .catch((err) => { logger.error('[Seed Demo] Failed:', err); process.exit(1); }); } export { seedDemoRequests, ensureDemoNonSubmittedDealers };