import { BadRequestException, Injectable, NotFoundException, } from '@nestjs/common'; import { Prisma } from '@prisma/client'; import { PrismaService } from '../../prisma/prisma.service'; import { TahesabConnectionsService } from './connections.service'; import { normalizeMandehResponse } from './tahesab-methods'; @Injectable() export class TahesabBalanceService { constructor( private readonly prisma: PrismaService, private readonly connections: TahesabConnectionsService, ) {} async getAssets( organizationId: string, personId: string, connectionId?: string, ) { const person = await this.prisma.person.findFirst({ where: { id: personId, organizationId }, }); if (!person) throw new NotFoundException('شخص یافت نشد.'); const resolvedId = await this.connections.resolveConnectionId( organizationId, connectionId, ); const link = await this.prisma.personAccountingLink.findFirst({ where: { personId, connectionId: resolvedId }, include: { connection: { select: { id: true, label: true, dbName: true, isDefault: true }, }, balanceCache: true, }, }); if (!link) { throw new BadRequestException( 'این شخص به اتصال ته‌حساب لینک نشده است. ابتدا تطبیق یا ثبت در ته‌حساب را انجام دهید.', ); } const { api } = await this.connections.getApi(organizationId, resolvedId); const raw = await api.getMandeHesabByCode(link.moshtariCode); const normalized = normalizeMandehResponse(raw); const cache = await this.prisma.accountingBalanceCache.upsert({ where: { linkId: link.id }, create: { linkId: link.id, connectionId: resolvedId, goldBalance: normalized.goldBalance, rialBalance: normalized.rialBalance, currencyBalance: normalized.currencyBalance, totalGoldEquiv: normalized.totalGoldEquiv, mandehDetail: normalized.mandehDetail as unknown as Prisma.InputJsonValue, rawResponse: normalized.raw as Prisma.InputJsonValue, fetchedAt: new Date(), }, update: { goldBalance: normalized.goldBalance, rialBalance: normalized.rialBalance, currencyBalance: normalized.currencyBalance, totalGoldEquiv: normalized.totalGoldEquiv, mandehDetail: normalized.mandehDetail as unknown as Prisma.InputJsonValue, rawResponse: normalized.raw as Prisma.InputJsonValue, fetchedAt: new Date(), }, }); await this.prisma.personAccountingLink.update({ where: { id: link.id }, data: { lastBalanceSyncedAt: cache.fetchedAt }, }); return { connectionId: resolvedId, connectionLabel: link.connection.label, dbName: link.connection.dbName, moshtariCode: link.moshtariCode, goldBalance: normalized.goldBalance, rialBalance: normalized.rialBalance, currencyBalance: normalized.currencyBalance, totalGoldEquiv: normalized.totalGoldEquiv, mandehDetail: normalized.mandehDetail, fetchedAt: cache.fetchedAt.toISOString(), }; } async getCachedOrFetch( organizationId: string, personId: string, connectionId?: string, refresh = true, ) { if (refresh) { return this.getAssets(organizationId, personId, connectionId); } const resolvedId = await this.connections.resolveConnectionId( organizationId, connectionId, ); const link = await this.prisma.personAccountingLink.findFirst({ where: { personId, connectionId: resolvedId }, include: { connection: { select: { label: true, dbName: true } }, balanceCache: true, }, }); if (!link?.balanceCache) { return this.getAssets(organizationId, personId, connectionId); } const c = link.balanceCache; return { connectionId: resolvedId, connectionLabel: link.connection.label, dbName: link.connection.dbName, moshtariCode: link.moshtariCode, goldBalance: c.goldBalance, rialBalance: c.rialBalance, currencyBalance: c.currencyBalance, totalGoldEquiv: c.totalGoldEquiv, mandehDetail: c.mandehDetail, fetchedAt: c.fetchedAt.toISOString(), }; } }