From b4b07eda6b058ac5566ef719ea03bb5cf1c36701 Mon Sep 17 00:00:00 2001 From: MOHAN Date: Fri, 17 Jul 2026 23:34:59 +0530 Subject: [PATCH] Add credit score provider pull --- src/credit-score/credit-score.controller.ts | 7 ++- src/credit-score/credit-score.service.ts | 50 ++++++++++++++++++++- src/credit-score/dto.ts | 14 ++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/credit-score/credit-score.controller.ts b/src/credit-score/credit-score.controller.ts index 261e2cf..74c7119 100644 --- a/src/credit-score/credit-score.controller.ts +++ b/src/credit-score/credit-score.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, Get, Post, Query } from "@nestjs/common"; import { CurrentUser } from "../common/decorators/current-user.decorator"; import { ok } from "../common/response"; import { CreditScoreService } from "./credit-score.service"; -import { CreateCreditScoreEntryDto } from "./dto"; +import { CreateCreditScoreEntryDto, PullCreditScoreDto } from "./dto"; @Controller("credit-score") export class CreditScoreController { @@ -22,4 +22,9 @@ export class CreditScoreController { async createEntry(@CurrentUser() userId: string, @Body() body: CreateCreditScoreEntryDto) { return ok(await this.creditScoreService.createEntry(userId, body)); } + + @Post("pull") + async pull(@CurrentUser() userId: string, @Body() body: PullCreditScoreDto) { + return ok(await this.creditScoreService.pullScore(userId, body)); + } } diff --git a/src/credit-score/credit-score.service.ts b/src/credit-score/credit-score.service.ts index 91f0efa..9b03f5a 100644 --- a/src/credit-score/credit-score.service.ts +++ b/src/credit-score/credit-score.service.ts @@ -2,7 +2,9 @@ import { BadRequestException, Injectable } from "@nestjs/common"; import { Prisma } from "@prisma/client"; import { NotificationsService } from "../notifications/notifications.service"; import { PrismaService } from "../prisma/prisma.service"; -import { CreateCreditScoreEntryDto } from "./dto"; +import { CreateCreditScoreEntryDto, PullCreditScoreDto } from "./dto"; + +const SUPPORTED_CREDIT_PROVIDERS = ["sandbox"]; @Injectable() export class CreditScoreService { @@ -79,6 +81,29 @@ export class CreditScoreService { }; } + async pullScore(userId: string, dto: PullCreditScoreDto) { + const provider = (dto.provider ?? process.env.CREDIT_SCORE_PROVIDER ?? "sandbox").toLowerCase(); + if (!SUPPORTED_CREDIT_PROVIDERS.includes(provider)) { + throw new BadRequestException("Configured credit-score provider is not supported by this build."); + } + + const pulled = await this.pullFromProvider(provider, userId, dto.bureau ?? "experian"); + return this.createEntry(userId, { + score: pulled.score, + bureau: pulled.bureau, + source: "provider", + model: pulled.model, + scoreDate: pulled.scoreDate, + factors: pulled.factors, + metadata: { + provider, + providerPullId: pulled.providerPullId, + consent: dto.consent ?? {}, + sandbox: provider === "sandbox", + }, + }); + } + async summary(userId: string) { const entries = await this.listEntries(userId, "all"); const latestByBureau = new Map(); @@ -118,4 +143,27 @@ export class CreditScoreService { if (bureau === "transunion") return "TransUnion"; return "Credit"; } + + private async pullFromProvider(provider: string, userId: string, bureau: "experian" | "equifax" | "transunion") { + if (provider !== "sandbox") { + throw new BadRequestException("Credit-score provider is not available."); + } + + const seed = Array.from(`${userId}:${bureau}:${new Date().toISOString().slice(0, 10)}`) + .reduce((sum, char) => sum + char.charCodeAt(0), 0); + const score = 660 + (seed % 90); + return { + score, + bureau, + model: "vantage_score_3", + scoreDate: new Date().toISOString(), + providerPullId: `sandbox_credit_${seed}_${Date.now()}`, + factors: { + paymentHistory: "good", + utilization: seed % 3 === 0 ? "moderate" : "low", + accountAge: "established", + inquiries: seed % 2 === 0 ? "low" : "moderate", + }, + }; + } } diff --git a/src/credit-score/dto.ts b/src/credit-score/dto.ts index 3290570..ddaeb5a 100644 --- a/src/credit-score/dto.ts +++ b/src/credit-score/dto.ts @@ -29,3 +29,17 @@ export class CreateCreditScoreEntryDto { @IsObject() metadata?: Record; } + +export class PullCreditScoreDto { + @IsOptional() + @IsIn(["experian", "equifax", "transunion"]) + bureau?: "experian" | "equifax" | "transunion"; + + @IsOptional() + @IsString() + provider?: string; + + @IsOptional() + @IsObject() + consent?: Record; +}