Add credit score provider pull
This commit is contained in:
parent
14dec26ccf
commit
b4b07eda6b
@ -2,7 +2,7 @@ import { Body, Controller, Get, Post, Query } from "@nestjs/common";
|
|||||||
import { CurrentUser } from "../common/decorators/current-user.decorator";
|
import { CurrentUser } from "../common/decorators/current-user.decorator";
|
||||||
import { ok } from "../common/response";
|
import { ok } from "../common/response";
|
||||||
import { CreditScoreService } from "./credit-score.service";
|
import { CreditScoreService } from "./credit-score.service";
|
||||||
import { CreateCreditScoreEntryDto } from "./dto";
|
import { CreateCreditScoreEntryDto, PullCreditScoreDto } from "./dto";
|
||||||
|
|
||||||
@Controller("credit-score")
|
@Controller("credit-score")
|
||||||
export class CreditScoreController {
|
export class CreditScoreController {
|
||||||
@ -22,4 +22,9 @@ export class CreditScoreController {
|
|||||||
async createEntry(@CurrentUser() userId: string, @Body() body: CreateCreditScoreEntryDto) {
|
async createEntry(@CurrentUser() userId: string, @Body() body: CreateCreditScoreEntryDto) {
|
||||||
return ok(await this.creditScoreService.createEntry(userId, body));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,9 @@ import { BadRequestException, Injectable } from "@nestjs/common";
|
|||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { NotificationsService } from "../notifications/notifications.service";
|
import { NotificationsService } from "../notifications/notifications.service";
|
||||||
import { PrismaService } from "../prisma/prisma.service";
|
import { PrismaService } from "../prisma/prisma.service";
|
||||||
import { CreateCreditScoreEntryDto } from "./dto";
|
import { CreateCreditScoreEntryDto, PullCreditScoreDto } from "./dto";
|
||||||
|
|
||||||
|
const SUPPORTED_CREDIT_PROVIDERS = ["sandbox"];
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreditScoreService {
|
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) {
|
async summary(userId: string) {
|
||||||
const entries = await this.listEntries(userId, "all");
|
const entries = await this.listEntries(userId, "all");
|
||||||
const latestByBureau = new Map<string, any>();
|
const latestByBureau = new Map<string, any>();
|
||||||
@ -118,4 +143,27 @@ export class CreditScoreService {
|
|||||||
if (bureau === "transunion") return "TransUnion";
|
if (bureau === "transunion") return "TransUnion";
|
||||||
return "Credit";
|
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",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,3 +29,17 @@ export class CreateCreditScoreEntryDto {
|
|||||||
@IsObject()
|
@IsObject()
|
||||||
metadata?: Record<string, unknown>;
|
metadata?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PullCreditScoreDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsIn(["experian", "equifax", "transunion"])
|
||||||
|
bureau?: "experian" | "equifax" | "transunion";
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
provider?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsObject()
|
||||||
|
consent?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user