Files
carmanagement/apps/api/src/modules/customers/customer.service.ts
T
2026-05-21 12:35:49 -04:00

101 lines
4.5 KiB
TypeScript

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,
}))
}