feat(loan-origination): tabbed CIC report dialog with real PDF parsing via pdfjs-dist
Extracts score, accounts, DPD payment history and enquiries directly from an uploaded bureau PDF (position-aware parsing, so blank DPD months are handled correctly) instead of always showing a simulated report, falling back to the simulated analysis when a file can't be read.
This commit is contained in:
@@ -29,7 +29,12 @@ import {
|
||||
summarizeBankStatement
|
||||
} from './bank-statement-analysis-dialog/bank-statement-analysis.util';
|
||||
import { CicReportAnalysisDialogComponent } from './cic-report-analysis-dialog/cic-report-analysis-dialog.component';
|
||||
import { generateCicReportAnalysis } from './cic-report-analysis-dialog/cic-report-analysis.util';
|
||||
import {
|
||||
CicReportAnalysis,
|
||||
CIC_KNOWN_BUREAUS,
|
||||
generateCicReportAnalysis
|
||||
} from './cic-report-analysis-dialog/cic-report-analysis.util';
|
||||
import { parseCicPdfReport } from './cic-report-analysis-dialog/cic-pdf-parser.util';
|
||||
import { FieldVisitDetailsDialogComponent } from './field-visit-details-dialog/field-visit-details-dialog.component';
|
||||
import {
|
||||
ApprovalField,
|
||||
@@ -2050,24 +2055,51 @@ I confirm that:
|
||||
}
|
||||
|
||||
// -------------------- CIC Upload --------------------
|
||||
onCicFileSelected(event: Event, a: LoanApplication): void {
|
||||
async onCicFileSelected(event: Event, a: LoanApplication): Promise<void> {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parsed: CicReportAnalysis | null = null;
|
||||
if (file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf')) {
|
||||
parsed = await parseCicPdfReport(file);
|
||||
}
|
||||
|
||||
if (parsed) {
|
||||
const knownBureau = (CIC_KNOWN_BUREAUS as readonly string[]).includes(parsed.bureau)
|
||||
? parsed.bureau
|
||||
: a.cicBureau;
|
||||
a.cicBureau = knownBureau as LoanApplication['cicBureau'];
|
||||
a.cibilScore = parsed.score;
|
||||
a.cicParsedAnalysis = parsed;
|
||||
a.cicAnalysisSource = 'PARSED';
|
||||
} else {
|
||||
a.cicParsedAnalysis = generateCicReportAnalysis(a);
|
||||
a.cicAnalysisSource = 'SIMULATED';
|
||||
}
|
||||
|
||||
uploadCicReport(a, file.name, this.currentUserName);
|
||||
input.value = '';
|
||||
this.openCicReportAnalysis(a);
|
||||
}
|
||||
|
||||
/** No real bureau API or PDF parser sits behind this mock pipeline, so the analysis shown here
|
||||
* is generated (deterministically, seeded off the application) from the cibilScore the "Check
|
||||
* Credit Score" step already pulled -- not read from the actual uploaded file. Auto-opens right
|
||||
* after upload, and reopenable afterwards via the "View Analysis" pill next to the Report row. */
|
||||
/** Reopens whatever analysis is already on the application -- the real parsed one if the last
|
||||
* upload actually yielded one, otherwise the simulated fallback -- generating and caching the
|
||||
* simulated version on first view rather than a fresh (and pointlessly different) one every
|
||||
* time this is clicked. */
|
||||
openCicReportAnalysis(a: LoanApplication): void {
|
||||
if (!a.cicParsedAnalysis) {
|
||||
a.cicParsedAnalysis = generateCicReportAnalysis(a);
|
||||
a.cicAnalysisSource = 'SIMULATED';
|
||||
}
|
||||
this.dialog.open(CicReportAnalysisDialogComponent, {
|
||||
data: { fileName: a.cicReportFileName, analysis: generateCicReportAnalysis(a) },
|
||||
data: {
|
||||
fileName: a.cicReportFileName,
|
||||
analysis: a.cicParsedAnalysis as CicReportAnalysis,
|
||||
wasParsedFromFile: a.cicAnalysisSource === 'PARSED'
|
||||
},
|
||||
width: '960px',
|
||||
maxWidth: '95vw'
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user