import { validateAndFlagLicense } from '../../services/licenseValidationService' import { uploadImage, deleteImage, resolveStoredFilePath } from '../../lib/storage' import { NotFoundError } from '../../http/errors' import { presentCustomer, presentCustomerList } from './customer.presenter' import * as repo from './customer.repo' export async function listCustomers(companyId: string, query: { page?: number; pageSize?: number; q?: string; flagged?: string }) { const page = query.page ?? 1 const pageSize = query.pageSize ?? 20 const { q, flagged } = query const safeQ = q ? q.trim().slice(0, 100) : undefined const where: any = { companyId } if (flagged !== undefined) where.flagged = flagged === 'true' if (safeQ) { where.OR = [ { firstName: { contains: safeQ, mode: 'insensitive' } }, { lastName: { contains: safeQ, mode: 'insensitive' } }, { email: { contains: safeQ, mode: 'insensitive' } }, ] } const [customers, total] = await repo.findMany(where, (page - 1) * pageSize, pageSize) return presentCustomerList(customers.map(presentCustomer), { total, page, pageSize, totalPages: Math.ceil(total / pageSize) }) } export async function getCustomer(id: string, companyId: string) { const customer = await repo.findById(id, companyId) if (!customer) throw new NotFoundError('Customer not found') return presentCustomer(customer) } export async function createCustomer(data: any, companyId: string) { const customer = await repo.create({ ...data, companyId, dateOfBirth: data.dateOfBirth ? new Date(data.dateOfBirth) : null, licenseExpiry: data.licenseExpiry ? new Date(data.licenseExpiry) : null, licenseIssuedAt: data.licenseIssuedAt ? new Date(data.licenseIssuedAt) : null, }) if (data.licenseExpiry) { await validateAndFlagLicense(customer.id).catch(() => null) } return presentCustomer(customer) } export async function updateCustomer(id: string, companyId: string, data: any) { const result = await repo.updateMany(id, companyId, { ...data, dateOfBirth: data.dateOfBirth ? new Date(data.dateOfBirth) : undefined, licenseExpiry: data.licenseExpiry ? new Date(data.licenseExpiry) : undefined, licenseIssuedAt: data.licenseIssuedAt ? new Date(data.licenseIssuedAt) : undefined, }) if (result.count === 0) throw new NotFoundError('Customer not found') if (data.licenseExpiry) await validateAndFlagLicense(id).catch(() => null) return presentCustomer(await repo.findUniqueOrThrow(id)) } export async function flagCustomer(id: string, companyId: string, reason?: string) { await repo.updateMany(id, companyId, { flagged: true, flagReason: reason ?? null }) } export async function unflagCustomer(id: string, companyId: string) { await repo.updateMany(id, companyId, { flagged: false, flagReason: null }) } export async function validateCustomerLicense(id: string, companyId: string) { const customer = await repo.findByIdSimple(id, companyId) if (!customer) throw new NotFoundError('Customer not found') return validateAndFlagLicense(customer.id) } export async function uploadLicenseImage(id: string, companyId: string, file: Express.Multer.File) { const customer = await repo.findByIdSimple(id, companyId) if (!customer) throw new NotFoundError('Customer not found') const url = await uploadImage(file.buffer, `companies/${companyId}/customers/${customer.id}`) if (customer.licenseImageUrl) { await deleteImage(customer.licenseImageUrl).catch(() => null) } return presentCustomer(await repo.updateById(customer.id, { licenseImageUrl: url })) } export async function getLicenseImageFile(id: string, companyId: string) { const customer = await repo.findByIdSimple(id, companyId) if (!customer || !customer.licenseImageUrl) throw new NotFoundError('License image not found') const filePath = resolveStoredFilePath(customer.licenseImageUrl) if (!filePath) throw new NotFoundError('License image not found') return filePath } export async function approveLicense(id: string, companyId: string, decision: 'APPROVE' | 'DENY', note: string | undefined, approverName: string) { const customer = await repo.findByIdSimple(id, companyId) if (!customer) throw new NotFoundError('Customer not found') return presentCustomer(await repo.updateById(customer.id, { licenseValidationStatus: decision === 'APPROVE' ? 'APPROVED' : 'DENIED', licenseApprovedBy: approverName, licenseApprovedAt: new Date(), licenseApprovalNote: note ?? null, })) }