import { Injectable, NotFoundException } from '@nestjs/common'; import { Prisma } from '@prisma/client'; import { PrismaService } from '../../prisma/prisma.service'; // passwordHash must never leave the API — every customer read goes through this. const PUBLIC_CUSTOMER_SELECT = { id: true, fullName: true, mobile: true, nationalCode: true, cityId: true, referredByAgentId: true, goldCreditLimitGrams: true, goldDebtGrams: true, fiatDebtRial: true, verificationStep: true, nationalIdImageUrl: true, businessLicenseUrl: true, shopImageUrl: true, isActive: true, isArchived: true, createdAt: true, updatedAt: true, } satisfies Prisma.CustomerSelect; /** * Every method here is reached only through CustomerAuthController's * token-derived /customer/me* routes, which pass the id from the JWT. * * There used to be a `list()` returning every active customer, because the two * apps' login screens downloaded it and matched the phone number in the * browser. It is gone: the login lookup now happens server-side inside * CustomerAuthService.requestOtp, which is what the reference did * (henza_server ApiMobileController.php:39-49). See SEC-08. */ @Injectable() export class CustomersService { constructor(private readonly prisma: PrismaService) {} async getOrThrow(customerId: string) { const customer = await this.prisma.customer.findUnique({ where: { id: customerId }, select: PUBLIC_CUSTOMER_SELECT, }); if (!customer) throw new NotFoundException(`Customer ${customerId} not found`); return customer; } getOrders(customerId: string) { return this.prisma.order.findMany({ where: { customerId }, include: { items: true }, orderBy: { createdAt: 'desc' }, }); } getLedgerEntries(customerId: string) { return this.prisma.ledgerEntry.findMany({ where: { customerId }, orderBy: { createdAt: 'desc' }, }); } }