import { Request, Response } from 'express'; import { CpcHistoryService } from '../services/cpc-cdc/CpcHistoryService'; import { CpcDocument } from '../models/CpcDocument'; import { appendCpcDocumentFilters, cpcWhereFromAndParts } from '../services/cpc-cdc/utils'; import ExcelJS from 'exceljs'; import { ResponseHandler } from '../utils/responseHandler'; import { Op } from 'sequelize'; export class CpcReportController { /** * Download Excel report for a specific claim */ async downloadReport(req: Request, res: Response) { try { const { claimId } = req.params; const { attempt } = req.query; const where: any = { [Op.or]: [ { claimId: claimId }, { bookingId: claimId } ] }; if (attempt) where.attemptNo = parseInt(attempt as string); const docs = await CpcDocument.findAll({ where, order: [['createdAt', 'DESC']] }); if (!docs || docs.length === 0) { return ResponseHandler.error(res, "No records found for this claim", 404); } const workbook = new ExcelJS.Workbook(); const sheet = workbook.addWorksheet('Validation Report'); // HEADERS const row1 = sheet.getRow(1); row1.values = [ 'Booking Type', 'Booking Number', 'Document Count', 'Document Name', 'Customer Name', '', '', '', '', 'PO Number /Authorisation Letter Number', '', '', '', '', 'Aadhar Number', '', '', '', '', 'PO Amount / Authorisation Letter Amount', '', '', '', '', 'Signature & Stamp Availability', '', '', '', '', 'Final Validation' ]; const row2 = sheet.getRow(2); row2.values = [ '', '', '', '', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching Availability', 'Accuracy Criteria', 'Success Ratio', '' ]; sheet.mergeCells('E1:I1'); sheet.mergeCells('J1:N1'); sheet.mergeCells('O1:S1'); sheet.mergeCells('T1:X1'); sheet.mergeCells('Y1:AC1'); sheet.mergeCells('A1:A2'); sheet.mergeCells('B1:B2'); sheet.mergeCells('C1:C2'); sheet.mergeCells('D1:D2'); sheet.mergeCells('AD1:AD2'); [row1, row2].forEach((r: any) => { r.font = { bold: true, size: 9 }; r.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }; r.eachCell((cell: any) => { cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFD9D9D9' } }; cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }; }); }); docs.forEach((doc: any, idx: number) => { const rowData = CpcHistoryService.getSummaryRow(doc, idx); const values = [ rowData.booking_type, rowData.booking_number, rowData.document_count, rowData.document_name, rowData.customer_name_group.msd, rowData.customer_name_group.ocr, rowData.customer_name_group.accuracy_pct, rowData.customer_name_group.criteria, rowData.customer_name_group.is_match, rowData.po_or_auth_number_group.msd, rowData.po_or_auth_number_group.ocr, rowData.po_or_auth_number_group.accuracy_pct, rowData.po_or_auth_number_group.criteria, rowData.po_or_auth_number_group.is_match, rowData.aadhaar_number_group.msd, rowData.aadhaar_number_group.ocr, rowData.aadhaar_number_group.accuracy_pct, rowData.aadhaar_number_group.criteria, rowData.aadhaar_number_group.is_match, rowData.amount_group.msd, rowData.amount_group.ocr, rowData.amount_group.accuracy_pct, rowData.amount_group.criteria, rowData.amount_group.is_match, rowData.stamp_group.msd, rowData.stamp_group.ocr, rowData.stamp_group.accuracy_pct, rowData.stamp_group.criteria, rowData.stamp_group.is_match, rowData.final_validation ]; const row = sheet.addRow(values); row.eachCell((cell: any, colNum: number) => { cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }; cell.font = { size: 8 }; cell.alignment = { vertical: 'middle', horizontal: 'center' }; if (cell.value === 'N.A.' && colNum > 4) { cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFF0000' } }; cell.font = { color: { argb: 'FFFFFFFF' }, size: 8, bold: true }; } }); }); sheet.addRow([]); sheet.addRow([]); const detailHeader = sheet.addRow(['Detailed Field-Wise Comparison']); detailHeader.font = { bold: true, size: 12 }; docs.forEach((doc: any) => { const docHeader = sheet.addRow([`Document: ${doc.documentType?.replace(/_/g, ' ')}`]); docHeader.font = { bold: true, size: 10 }; const subHeader = sheet.addRow(['Field', 'Expected', 'Extracted (OCR)', 'Accuracy %', 'Criteria', 'Status', 'Message']); const finalResults = CpcHistoryService.getDetailedFieldResults(doc); finalResults.forEach((f: any) => { sheet.addRow([ f.field.replace(/_/g, ' '), f.expected || '-', f.extracted || 'Not extracted', f.accuracy, f.criteria, f.pass ? 'PASS' : 'FAIL', f.message ]); }); sheet.addRow([]); }); res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); res.setHeader('Content-Disposition', `attachment; filename=Report_${claimId}.xlsx`); await workbook.xlsx.write(res); res.end(); } catch (error: any) { return ResponseHandler.error(res, error.message || "Report generation failed", 500); } } /** * Download Master Audit Report for all filtered documents */ async downloadAllReport(req: Request, res: Response) { try { const { search, status, type } = req.query; const andParts: Record[] = []; appendCpcDocumentFilters(andParts, { type: type as string, status: status as string, search: search as string, searchIncludeId: false }); const where = cpcWhereFromAndParts(andParts); const docs = await CpcDocument.findAll({ where, order: [['createdAt', 'DESC']] }); const workbook = new ExcelJS.Workbook(); const sheet = workbook.addWorksheet('Master Audit Trail'); const row1 = sheet.getRow(1); row1.values = ['Booking Type', 'Booking Number', 'Doc ID', 'Document Name', 'Customer Name', '', '', '', '', 'PO Number /Authorisation Letter Number', '', '', '', '', 'Aadhar Number', '', '', '', '', 'PO Amount / Authorisation Letter Amount', '', '', '', '', 'Signature & Stamp Availability', '', '', '', '', 'Final Validation']; const row2 = sheet.getRow(2); row2.values = ['', '', '', '', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching %', 'Accuracy Criteria', 'Is Match the Accuracy', 'Expected', 'OCR', 'Accuracy Matching Availability', 'Accuracy Criteria', 'Success Ratio', '']; sheet.mergeCells('E1:I1'); sheet.mergeCells('J1:N1'); sheet.mergeCells('O1:S1'); sheet.mergeCells('T1:X1'); sheet.mergeCells('Y1:AC1'); sheet.mergeCells('A1:A2'); sheet.mergeCells('B1:B2'); sheet.mergeCells('C1:C2'); sheet.mergeCells('D1:D2'); sheet.mergeCells('AD1:AD2'); [row1, row2].forEach((r: any) => { r.font = { bold: true, size: 9 }; r.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }; r.eachCell((cell: any) => { cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFD9D9D9' } }; cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }; }); }); docs.forEach((doc: any, idx: number) => { const rowData = CpcHistoryService.getSummaryRow(doc, idx); const values = [ rowData.booking_type, rowData.booking_number, String(doc.id).slice(0, 8), rowData.document_name, rowData.customer_name_group.msd, rowData.customer_name_group.ocr, rowData.customer_name_group.accuracy_pct, rowData.customer_name_group.criteria, rowData.customer_name_group.is_match, rowData.po_or_auth_number_group.msd, rowData.po_or_auth_number_group.ocr, rowData.po_or_auth_number_group.accuracy_pct, rowData.po_or_auth_number_group.criteria, rowData.po_or_auth_number_group.is_match, rowData.aadhaar_number_group.msd, rowData.aadhaar_number_group.ocr, rowData.aadhaar_number_group.accuracy_pct, rowData.aadhaar_number_group.criteria, rowData.aadhaar_number_group.is_match, rowData.amount_group.msd, rowData.amount_group.ocr, rowData.amount_group.accuracy_pct, rowData.amount_group.criteria, rowData.amount_group.is_match, rowData.stamp_group.msd, rowData.stamp_group.ocr, rowData.stamp_group.accuracy_pct, rowData.stamp_group.criteria, rowData.stamp_group.is_match, rowData.final_validation ]; const row = sheet.addRow(values); }); res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); res.setHeader('Content-Disposition', `attachment; filename=Master_Audit_Report.xlsx`); await workbook.xlsx.write(res); res.end(); } catch (error: any) { return ResponseHandler.error(res, error.message || "Master report failed", 500); } } }